summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.clang-tidy13
-rw-r--r--.gitattributes4
-rw-r--r--.gitlab-ci.yml399
-rw-r--r--.gitlab/.gitignore2
-rw-r--r--.gitlab/artifacts.yml31
-rw-r--r--.gitlab/ci/CMakeCPack.cmake3
-rwxr-xr-x.gitlab/ci/cmake.ps114
-rwxr-xr-x.gitlab/ci/codespell.sh16
-rw-r--r--.gitlab/ci/configure_cuda11.8_minimal_nvidia.cmake3
-rw-r--r--.gitlab/ci/configure_debian10_aarch64_ninja.cmake2
-rw-r--r--.gitlab/ci/configure_debian10_iwyu.cmake2
-rw-r--r--.gitlab/ci/configure_debian10_ninja.cmake2
-rw-r--r--.gitlab/ci/configure_fedora36_clang_analyzer.cmake1
-rw-r--r--.gitlab/ci/configure_fedora36_tidy.cmake3
-rw-r--r--.gitlab/ci/configure_fedora37_asan.cmake (renamed from .gitlab/ci/configure_fedora36_asan.cmake)2
-rw-r--r--.gitlab/ci/configure_fedora37_clang_analyzer.cmake1
-rw-r--r--.gitlab/ci/configure_fedora37_common.cmake (renamed from .gitlab/ci/configure_fedora36_common.cmake)0
-rw-r--r--.gitlab/ci/configure_fedora37_common_clang.cmake6
-rw-r--r--.gitlab/ci/configure_fedora37_extdeps.cmake (renamed from .gitlab/ci/configure_fedora36_extdeps.cmake)0
-rw-r--r--.gitlab/ci/configure_fedora37_makefiles.cmake (renamed from .gitlab/ci/configure_fedora36_makefiles.cmake)2
-rw-r--r--.gitlab/ci/configure_fedora37_makefiles_clang.cmake1
-rw-r--r--.gitlab/ci/configure_fedora37_ninja.cmake (renamed from .gitlab/ci/configure_fedora36_ninja.cmake)3
-rw-r--r--.gitlab/ci/configure_fedora37_ninja_clang.cmake1
-rw-r--r--.gitlab/ci/configure_fedora37_ninja_multi.cmake (renamed from .gitlab/ci/configure_fedora36_ninja_multi.cmake)0
-rw-r--r--.gitlab/ci/configure_fedora37_sphinx.cmake (renamed from .gitlab/ci/configure_fedora36_sphinx.cmake)0
-rw-r--r--.gitlab/ci/configure_fedora37_sphinx_package.cmake (renamed from .gitlab/ci/configure_fedora36_sphinx_package.cmake)0
-rw-r--r--.gitlab/ci/configure_fedora37_tidy.cmake5
-rw-r--r--.gitlab/ci/configure_linux_clang_cxx_modules_ninja.cmake4
-rw-r--r--.gitlab/ci/configure_linux_clang_cxx_modules_ninja_multi.cmake4
-rw-r--r--.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake2
-rw-r--r--.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake2
-rw-r--r--.gitlab/ci/configure_macos_arm64_ninja.cmake4
-rw-r--r--.gitlab/ci/configure_macos_x86_64_makefiles.cmake4
-rw-r--r--.gitlab/ci/configure_macos_x86_64_ninja.cmake4
-rw-r--r--.gitlab/ci/configure_mingw_osdn_io_common.cmake5
-rw-r--r--.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake1
-rw-r--r--.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake1
-rw-r--r--.gitlab/ci/configure_nvhpc_ninja.cmake5
-rw-r--r--.gitlab/ci/configure_windows_arm64_vs2022.cmake1
-rw-r--r--.gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake8
-rw-r--r--.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake2
-rw-r--r--.gitlab/ci/configure_windows_package_common.cmake2
-rw-r--r--.gitlab/ci/configure_windows_vs2022_x64.cmake3
-rw-r--r--.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake1
-rw-r--r--.gitlab/ci/ctest_build.cmake30
-rw-r--r--.gitlab/ci/ctest_exclusions.cmake7
-rw-r--r--.gitlab/ci/ctest_memcheck_fedora37_asan.lsan.supp (renamed from .gitlab/ci/ctest_memcheck_fedora36_asan.lsan.supp)0
-rw-r--r--.gitlab/ci/cxx_modules_rules_clang.cmake18
-rw-r--r--.gitlab/ci/docker/clang_cxx_modules/Dockerfile13
-rwxr-xr-x.gitlab/ci/docker/clang_cxx_modules/install_cmake_deps.sh7
-rwxr-xr-x.gitlab/ci/docker/clang_cxx_modules/install_deps.sh7
-rwxr-xr-x.gitlab/ci/docker/clang_cxx_modules/install_llvm.sh39
-rw-r--r--.gitlab/ci/docker/cuda10.2/Dockerfile2
-rw-r--r--.gitlab/ci/docker/cuda11.6/Dockerfile2
-rw-r--r--.gitlab/ci/docker/cuda11.8-minimal/Dockerfile5
-rwxr-xr-x.gitlab/ci/docker/cuda11.8-minimal/install_deps.sh26
-rw-r--r--.gitlab/ci/docker/cuda9.2/Dockerfile2
-rw-r--r--.gitlab/ci/docker/debian10-aarch64/Dockerfile29
-rw-r--r--.gitlab/ci/docker/debian10-aarch64/deps_packages.lst90
-rw-r--r--.gitlab/ci/docker/debian10-aarch64/docker-clean (renamed from Tests/RunCMake/file/DOWNLOAD-unused-argument.txt)0
-rw-r--r--.gitlab/ci/docker/debian10-aarch64/dpkg-exclude21
-rwxr-xr-x.gitlab/ci/docker/debian10-aarch64/install_deps.sh101
-rw-r--r--.gitlab/ci/docker/debian10/Dockerfile73
-rw-r--r--.gitlab/ci/docker/debian10/deps_packages.lst96
-rw-r--r--.gitlab/ci/docker/debian10/docker-clean (renamed from Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt)0
-rw-r--r--.gitlab/ci/docker/debian10/dpkg-exclude21
-rwxr-xr-x.gitlab/ci/docker/debian10/install_deps.sh113
-rwxr-xr-x.gitlab/ci/docker/debian10/install_iwyu.sh13
-rwxr-xr-x.gitlab/ci/docker/debian10/install_rvm.sh12
-rw-r--r--.gitlab/ci/docker/debian10/iwyu_packages.lst9
-rw-r--r--.gitlab/ci/docker/debian10/rvm_packages.lst25
-rw-r--r--.gitlab/ci/docker/fedora36/Dockerfile33
-rwxr-xr-x.gitlab/ci/docker/fedora36/install_deps.sh132
-rwxr-xr-x.gitlab/ci/docker/fedora36/install_rvm.sh19
-rw-r--r--.gitlab/ci/docker/fedora37/Dockerfile73
-rw-r--r--.gitlab/ci/docker/fedora37/clang_tidy_headers_packages.lst4
-rw-r--r--.gitlab/ci/docker/fedora37/deps_packages.lst110
-rwxr-xr-x.gitlab/ci/docker/fedora37/install_clang_tidy_headers.sh (renamed from .gitlab/ci/docker/fedora36/install_clang_tidy_headers.sh)12
-rwxr-xr-x.gitlab/ci/docker/fedora37/install_deps.sh31
-rwxr-xr-x.gitlab/ci/docker/fedora37/install_iwyu.sh (renamed from .gitlab/ci/docker/fedora36/install_iwyu.sh)14
-rwxr-xr-x.gitlab/ci/docker/fedora37/install_rvm.sh25
-rw-r--r--.gitlab/ci/docker/fedora37/iwyu_packages.lst7
-rw-r--r--.gitlab/ci/docker/fedora37/rvm_packages.lst18
-rw-r--r--.gitlab/ci/docker/nvhpc22.11/Dockerfile6
-rwxr-xr-x.gitlab/ci/docker/nvhpc22.11/install_deps.sh11
-rw-r--r--.gitlab/ci/env_fedora37_asan.sh (renamed from .gitlab/ci/env_fedora36_asan.sh)0
-rw-r--r--.gitlab/ci/env_fedora37_clang_analyzer.sh (renamed from .gitlab/ci/env_fedora36_clang_analyzer.sh)0
-rw-r--r--.gitlab/ci/env_fedora37_common_clang.sh4
-rw-r--r--.gitlab/ci/env_fedora37_extdeps.sh (renamed from .gitlab/ci/env_fedora36_extdeps.sh)0
-rw-r--r--.gitlab/ci/env_fedora37_makefiles.cmake (renamed from .gitlab/ci/env_fedora36_makefiles.cmake)0
-rw-r--r--.gitlab/ci/env_fedora37_makefiles.sh (renamed from .gitlab/ci/env_fedora36_ninja_multi.sh)0
-rw-r--r--.gitlab/ci/env_fedora37_makefiles_clang.sh1
-rw-r--r--.gitlab/ci/env_fedora37_ninja.sh (renamed from .gitlab/ci/env_fedora36_ninja.sh)0
-rw-r--r--.gitlab/ci/env_fedora37_ninja_clang.sh1
-rw-r--r--.gitlab/ci/env_fedora37_ninja_multi.sh (renamed from .gitlab/ci/env_fedora36_makefiles.sh)0
-rw-r--r--.gitlab/ci/env_macos_arm64_ninja.sh1
-rw-r--r--.gitlab/ci/env_macos_x86_64_makefiles.sh1
-rw-r--r--.gitlab/ci/env_macos_x86_64_ninja.sh1
-rwxr-xr-x.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps13
-rwxr-xr-x.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps15
-rw-r--r--.gitlab/ci/env_nvhpc_ninja.sh5
-rwxr-xr-x.gitlab/ci/mingw.ps125
-rw-r--r--.gitlab/ci/openmp-env.sh3
-rwxr-xr-x.gitlab/ci/openmp.sh32
-rw-r--r--.gitlab/ci/package_info.cmake.in1
-rw-r--r--.gitlab/ci/package_macos.sh12
-rwxr-xr-x.gitlab/ci/package_windows.ps17
-rw-r--r--.gitlab/ci/package_windows_build.cmake41
-rwxr-xr-x.gitlab/ci/post_build.ps14
-rwxr-xr-x.gitlab/ci/post_build.sh18
-rw-r--r--.gitlab/ci/post_build_macos10.10_package.sh1
-rw-r--r--.gitlab/ci/post_build_macos_package.sh1
-rwxr-xr-x.gitlab/ci/post_build_windows_arm64_package.ps11
-rwxr-xr-x.gitlab/ci/post_build_windows_i386_package.ps11
-rwxr-xr-x.gitlab/ci/post_build_windows_x86_64_package.ps11
-rwxr-xr-x.gitlab/ci/pre_build.ps14
-rwxr-xr-x.gitlab/ci/pre_build.sh18
-rw-r--r--.gitlab/ci/pre_build_fedora37_tidy.sh9
-rwxr-xr-x.gitlab/ci/python-env.ps14
-rwxr-xr-x.gitlab/ci/qt-env.ps110
-rw-r--r--.gitlab/os-linux.yml180
-rw-r--r--.gitlab/os-macos.yml27
-rw-r--r--.gitlab/os-windows.yml110
-rw-r--r--.gitlab/rules.yml14
-rw-r--r--.gitlab/upload.yml8
-rw-r--r--Auxiliary/vim/syntax/cmake.vim1
-rw-r--r--CMakeCPack.cmake4
-rw-r--r--CMakeLists.txt63
-rw-r--r--CompileFlags.cmake5
-rw-r--r--Copyright.txt2
-rw-r--r--Help/command/DEVICE_LINK_OPTIONS.txt8
-rw-r--r--Help/command/GENEX_NOTE.txt6
-rw-r--r--Help/command/SUPPORTED_LANGUAGES.txt25
-rw-r--r--Help/command/add_compile_definitions.rst14
-rw-r--r--Help/command/add_compile_options.rst31
-rw-r--r--Help/command/add_custom_command.rst79
-rw-r--r--Help/command/add_custom_target.rst9
-rw-r--r--Help/command/add_definitions.rst9
-rw-r--r--Help/command/add_dependencies.rst13
-rw-r--r--Help/command/add_executable.rst5
-rw-r--r--Help/command/add_library.rst13
-rw-r--r--Help/command/add_link_options.rst13
-rw-r--r--Help/command/block.rst6
-rw-r--r--Help/command/build_name.rst2
-rw-r--r--Help/command/cmake_host_system_information.rst2
-rw-r--r--Help/command/cmake_minimum_required.rst5
-rw-r--r--Help/command/cmake_parse_arguments.rst6
-rw-r--r--Help/command/cmake_path.rst40
-rw-r--r--Help/command/cmake_policy.rst5
-rw-r--r--Help/command/configure_file.rst11
-rw-r--r--Help/command/ctest_build.rst2
-rw-r--r--Help/command/ctest_configure.rst2
-rw-r--r--Help/command/ctest_coverage.rst2
-rw-r--r--Help/command/ctest_empty_binary_directory.rst4
-rw-r--r--Help/command/ctest_memcheck.rst2
-rw-r--r--Help/command/ctest_read_custom_files.rst4
-rw-r--r--Help/command/ctest_run_script.rst2
-rw-r--r--Help/command/ctest_sleep.rst4
-rw-r--r--Help/command/ctest_start.rst2
-rw-r--r--Help/command/ctest_submit.rst4
-rw-r--r--Help/command/ctest_test.rst4
-rw-r--r--Help/command/ctest_update.rst2
-rw-r--r--Help/command/ctest_upload.rst2
-rw-r--r--Help/command/define_property.rst6
-rw-r--r--Help/command/enable_language.rst21
-rw-r--r--Help/command/exec_program.rst2
-rw-r--r--Help/command/execute_process.rst74
-rw-r--r--Help/command/export_library_dependencies.rst2
-rw-r--r--Help/command/file.rst27
-rw-r--r--Help/command/find_package.rst3
-rw-r--r--Help/command/foreach.rst6
-rw-r--r--Help/command/function.rst1
-rw-r--r--Help/command/get_cmake_property.rst7
-rw-r--r--Help/command/get_directory_property.rst7
-rw-r--r--Help/command/get_filename_component.rst5
-rw-r--r--Help/command/get_property.rst6
-rw-r--r--Help/command/get_source_file_property.rst9
-rw-r--r--Help/command/get_target_property.rst8
-rw-r--r--Help/command/get_test_property.rst6
-rw-r--r--Help/command/if.rst14
-rw-r--r--Help/command/include_directories.rst11
-rw-r--r--Help/command/include_guard.rst2
-rw-r--r--Help/command/install.rst4
-rw-r--r--Help/command/install_files.rst6
-rw-r--r--Help/command/install_programs.rst4
-rw-r--r--Help/command/install_targets.rst2
-rw-r--r--Help/command/link_directories.rst6
-rw-r--r--Help/command/load_command.rst4
-rw-r--r--Help/command/macro.rst6
-rw-r--r--Help/command/make_directory.rst2
-rw-r--r--Help/command/message.rst55
-rw-r--r--Help/command/output_required_files.rst2
-rw-r--r--Help/command/project.rst19
-rw-r--r--Help/command/remove.rst2
-rw-r--r--Help/command/return.rst5
-rw-r--r--Help/command/set.rst5
-rw-r--r--Help/command/set_directory_properties.rst7
-rw-r--r--Help/command/set_property.rst11
-rw-r--r--Help/command/set_source_files_properties.rst11
-rw-r--r--Help/command/set_target_properties.rst8
-rw-r--r--Help/command/set_tests_properties.rst8
-rw-r--r--Help/command/string.rst11
-rw-r--r--Help/command/subdir_depends.rst2
-rw-r--r--Help/command/subdirs.rst2
-rw-r--r--Help/command/target_compile_definitions.rst19
-rw-r--r--Help/command/target_compile_features.rst22
-rw-r--r--Help/command/target_compile_options.rst28
-rw-r--r--Help/command/target_include_directories.rst19
-rw-r--r--Help/command/target_link_directories.rst19
-rw-r--r--Help/command/target_link_libraries.rst16
-rw-r--r--Help/command/target_link_options.rst18
-rw-r--r--Help/command/target_precompile_headers.rst38
-rw-r--r--Help/command/target_sources.rst14
-rw-r--r--Help/command/try_compile.rst68
-rw-r--r--Help/command/try_run.rst42
-rw-r--r--Help/command/unset.rst5
-rw-r--r--Help/command/use_mangled_mesa.rst2
-rw-r--r--Help/command/utility_source.rst2
-rw-r--r--Help/command/variable_requires.rst2
-rw-r--r--Help/command/while.rst8
-rw-r--r--Help/command/write_file.rst2
-rw-r--r--Help/cpack_gen/archive.rst56
-rw-r--r--Help/cpack_gen/deb.rst212
-rw-r--r--Help/cpack_gen/dmg.rst32
-rw-r--r--Help/cpack_gen/freebsd.rst56
-rw-r--r--Help/cpack_gen/nuget.rst113
-rw-r--r--Help/cpack_gen/rpm.rst445
-rw-r--r--Help/dev/experimental.rst36
-rw-r--r--Help/dev/maint.rst1
-rw-r--r--Help/dev/source.rst2
-rw-r--r--Help/envvar/ASM_DIALECT.rst10
-rw-r--r--Help/envvar/ASM_DIALECTFLAGS.rst1
-rw-r--r--Help/envvar/CTEST_NO_TESTS_ACTION.rst14
-rw-r--r--Help/envvar/PackageName_ROOT.rst8
-rw-r--r--Help/generator/Ninja Multi-Config.rst28
-rw-r--r--Help/generator/Xcode.rst2
-rw-r--r--Help/guide/importing-exporting/index.rst3
-rw-r--r--Help/guide/tutorial/Adding Export Configuration.rst6
-rw-r--r--Help/guide/tutorial/Adding Support for a Testing Dashboard.rst95
-rw-r--r--Help/guide/tutorial/Adding System Introspection.rst153
-rw-r--r--Help/guide/tutorial/Installing and Testing.rst8
-rw-r--r--Help/guide/tutorial/Selecting Static or Shared Libraries.rst2
-rw-r--r--Help/guide/tutorial/Step12/CMakeLists.txt4
-rw-r--r--Help/guide/tutorial/Step5/CMakeLists.txt4
-rw-r--r--Help/guide/tutorial/Step6/CMakeLists.txt1
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt20
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx10
-rw-r--r--Help/guide/using-dependencies/index.rst2
-rw-r--r--Help/index.rst1
-rw-r--r--Help/manual/ccmake.1.rst2
-rw-r--r--Help/manual/cmake-buildsystem.7.rst10
-rw-r--r--Help/manual/cmake-compile-features.7.rst22
-rw-r--r--Help/manual/cmake-configure-log.7.rst334
-rw-r--r--Help/manual/cmake-developer.7.rst2
-rw-r--r--Help/manual/cmake-env-variables.7.rst1
-rw-r--r--Help/manual/cmake-file-api.7.rst75
-rw-r--r--Help/manual/cmake-generator-expressions.7.rst27
-rw-r--r--Help/manual/cmake-gui.1.rst2
-rw-r--r--Help/manual/cmake-language.7.rst25
-rw-r--r--Help/manual/cmake-modules.7.rst6
-rw-r--r--Help/manual/cmake-policies.7.rst7
-rw-r--r--Help/manual/cmake-properties.7.rst7
-rw-r--r--Help/manual/cmake-variables.7.rst3
-rw-r--r--Help/manual/cmake.1.rst48
-rw-r--r--Help/manual/cpack.1.rst22
-rw-r--r--Help/manual/ctest.1.rst23
-rw-r--r--Help/policy/CMP0053.rst2
-rw-r--r--Help/policy/CMP0101.rst24
-rw-r--r--Help/policy/CMP0143.rst30
-rw-r--r--Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst2
-rw-r--r--Help/prop_dir/COMPILE_DEFINITIONS.rst3
-rw-r--r--Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst5
-rw-r--r--Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst6
-rw-r--r--Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst2
-rw-r--r--Help/prop_gbl/JOB_POOLS.rst6
-rw-r--r--Help/prop_gbl/USE_FOLDERS.rst19
-rw-r--r--Help/prop_sf/COMPILE_DEFINITIONS.rst3
-rw-r--r--Help/prop_sf/CXX_SCAN_FOR_MODULES.rst24
-rw-r--r--Help/prop_sf/SKIP_AUTOUIC.rst2
-rw-r--r--Help/prop_test/LABELS.rst2
-rw-r--r--Help/prop_test/TIMEOUT_AFTER_MATCH.rst6
-rw-r--r--Help/prop_tgt/AUTOGEN_BUILD_DIR.rst2
-rw-r--r--Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst10
-rw-r--r--Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst6
-rw-r--r--Help/prop_tgt/AUTOMOC.rst18
-rw-r--r--Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst4
-rw-r--r--Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst2
-rw-r--r--Help/prop_tgt/AUTOMOC_EXECUTABLE.rst2
-rw-r--r--Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst4
-rw-r--r--Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst4
-rw-r--r--Help/prop_tgt/AUTORCC.rst14
-rw-r--r--Help/prop_tgt/AUTORCC_EXECUTABLE.rst2
-rw-r--r--Help/prop_tgt/AUTOUIC.rst10
-rw-r--r--Help/prop_tgt/AUTOUIC_EXECUTABLE.rst2
-rw-r--r--Help/prop_tgt/BUILD_RPATH.rst29
-rw-r--r--Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst27
-rw-r--r--Help/prop_tgt/COMPILE_DEFINITIONS.rst3
-rw-r--r--Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst9
-rw-r--r--Help/prop_tgt/CXX_SCAN_FOR_MODULES.rst27
-rw-r--r--Help/prop_tgt/DEFINE_SYMBOL.rst8
-rw-r--r--Help/prop_tgt/FOLDER.rst19
-rw-r--r--Help/prop_tgt/INSTALL_NAME_DIR.rst9
-rw-r--r--Help/prop_tgt/INSTALL_RPATH.rst26
-rw-r--r--Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst2
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst1
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst1
-rw-r--r--Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst1
-rw-r--r--Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst1
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst1
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst1
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst4
-rw-r--r--Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst2
-rw-r--r--Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst29
-rw-r--r--Help/prop_tgt/LINK_OPTIONS.rst4
-rw-r--r--Help/prop_tgt/OBJCXX_EXTENSIONS.rst2
-rw-r--r--Help/prop_tgt/OBJCXX_STANDARD.rst2
-rw-r--r--Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst2
-rw-r--r--Help/prop_tgt/OBJC_EXTENSIONS.rst2
-rw-r--r--Help/prop_tgt/OBJC_STANDARD.rst2
-rw-r--r--Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst2
-rw-r--r--Help/prop_tgt/SKIP_BUILD_RPATH.rst3
-rw-r--r--Help/prop_tgt/UNITY_BUILD_MODE.rst2
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type.rst14
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type_CODE_SIGN_ON_COPY.rst3
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type_PATH.rst3
-rw-r--r--Help/prop_tgt/XCODE_EMBED_type_REMOVE_HEADERS_ON_COPY.rst6
-rw-r--r--Help/release/3.15.rst50
-rw-r--r--Help/release/3.17.rst2
-rw-r--r--Help/release/3.18.rst9
-rw-r--r--Help/release/3.20.rst4
-rw-r--r--Help/release/3.23.rst4
-rw-r--r--Help/release/3.26.rst171
-rw-r--r--Help/release/3.9.rst6
-rw-r--r--Help/release/index.rst1
-rw-r--r--Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst2
-rw-r--r--Help/variable/CMAKE_AUTOGEN_PARALLEL.rst2
-rw-r--r--Help/variable/CMAKE_AUTOGEN_VERBOSE.rst4
-rw-r--r--Help/variable/CMAKE_BINARY_DIR.rst2
-rw-r--r--Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst3
-rw-r--r--Help/variable/CMAKE_CONFIGURATION_TYPES.rst3
-rw-r--r--Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst4
-rw-r--r--Help/variable/CMAKE_CURRENT_BINARY_DIR.rst2
-rw-r--r--Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst2
-rw-r--r--Help/variable/CMAKE_CXX_SCAN_FOR_MODULES.rst15
-rw-r--r--Help/variable/CMAKE_DEFAULT_CONFIGS.rst2
-rw-r--r--Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst2
-rw-r--r--Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst2
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst2
-rw-r--r--Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst2
-rw-r--r--Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst2
-rw-r--r--Help/variable/CMAKE_GENERATOR_INSTANCE.rst21
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst4
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst4
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst4
-rw-r--r--Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst4
-rw-r--r--Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst4
-rw-r--r--Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst15
-rw-r--r--Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst4
-rw-r--r--Help/variable/CMAKE_MODULE_PATH.rst9
-rw-r--r--Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst3
-rw-r--r--Help/variable/CMAKE_SKIP_BUILD_RPATH.rst10
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst2
-rw-r--r--Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst5
-rw-r--r--Help/variable/CMAKE_SKIP_RPATH.rst6
-rw-r--r--Help/variable/CMAKE_SOURCE_DIR.rst2
-rw-r--r--Help/variable/CMAKE_STAGING_PREFIX.rst4
-rw-r--r--Help/variable/CMAKE_TASKING_TOOLSET.rst2
-rw-r--r--Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER.rst14
-rw-r--r--Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt18
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst2
-rw-r--r--Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst2
-rw-r--r--Help/variable/GHSMULTI.rst2
-rw-r--r--Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt4
-rw-r--r--Help/variable/PackageName_ROOT.rst8
-rw-r--r--Modules/BasicConfigVersion-AnyNewerVersion.cmake.in18
-rw-r--r--Modules/BasicConfigVersion-ExactVersion.cmake.in18
-rw-r--r--Modules/BasicConfigVersion-SameMajorVersion.cmake.in18
-rw-r--r--Modules/BasicConfigVersion-SameMinorVersion.cmake.in18
-rw-r--r--Modules/BundleUtilities.cmake7
-rw-r--r--Modules/CMakeASM_MARMASMInformation.cmake24
-rw-r--r--Modules/CMakeCCompilerABI.c3
-rw-r--r--Modules/CMakeCheckCompilerFlagCommonPatterns.cmake1
-rw-r--r--Modules/CMakeDetermineASM_MARMASMCompiler.cmake18
-rw-r--r--Modules/CMakeDetermineCUDACompiler.cmake12
-rw-r--r--Modules/CMakeDetermineCompilerABI.cmake12
-rw-r--r--Modules/CMakeDetermineCompilerId.cmake61
-rw-r--r--Modules/CMakeDetermineFortranCompiler.cmake7
-rw-r--r--Modules/CMakeDetermineSystem.cmake65
-rw-r--r--Modules/CMakeFindDependencyMacro.cmake84
-rw-r--r--Modules/CMakeFortranCompiler.cmake.in2
-rw-r--r--Modules/CMakeGenericSystem.cmake12
-rw-r--r--Modules/CMakeMSYSFindMake.cmake11
-rw-r--r--Modules/CMakePackageConfigHelpers.cmake12
-rw-r--r--Modules/CMakeSwiftInformation.cmake41
-rw-r--r--Modules/CMakeTestASM_MARMASMCompiler.cmake13
-rw-r--r--Modules/CMakeTestCCompiler.cmake6
-rw-r--r--Modules/CMakeTestCSharpCompiler.cmake6
-rw-r--r--Modules/CMakeTestCUDACompiler.cmake8
-rw-r--r--Modules/CMakeTestCXXCompiler.cmake6
-rw-r--r--Modules/CMakeTestFortranCompiler.cmake12
-rw-r--r--Modules/CMakeTestHIPCompiler.cmake6
-rw-r--r--Modules/CMakeTestOBJCCompiler.cmake6
-rw-r--r--Modules/CMakeTestOBJCXXCompiler.cmake6
-rw-r--r--Modules/CMakeTestSwiftCompiler.cmake6
-rw-r--r--Modules/CPack.cmake2
-rw-r--r--Modules/CUDA/architectures.cmake8
-rw-r--r--Modules/CheckFortranFunctionExists.cmake7
-rw-r--r--Modules/CheckFortranSourceCompiles.cmake12
-rw-r--r--Modules/CheckFortranSourceRuns.cmake10
-rw-r--r--Modules/CheckFunctionExists.cmake8
-rw-r--r--Modules/CheckIPOSupported.cmake3
-rw-r--r--Modules/CheckIncludeFile.cmake10
-rw-r--r--Modules/CheckIncludeFileCXX.cmake10
-rw-r--r--Modules/CheckIncludeFiles.cmake10
-rw-r--r--Modules/CheckLanguage.cmake4
-rw-r--r--Modules/CheckLibraryExists.cmake10
-rw-r--r--Modules/CheckPrototypeDefinition.cmake8
-rw-r--r--Modules/CheckSourceCompiles.cmake30
-rw-r--r--Modules/CheckSourceRuns.cmake30
-rw-r--r--Modules/CheckSymbolExists.cmake12
-rw-r--r--Modules/CheckTypeSize.cmake5
-rw-r--r--Modules/CheckVariableExists.cmake8
-rw-r--r--Modules/Compiler/Clang-FindBinUtils.cmake11
-rw-r--r--Modules/Compiler/Clang.cmake2
-rw-r--r--Modules/Compiler/GNU.cmake14
-rw-r--r--Modules/Compiler/IAR.cmake38
-rw-r--r--Modules/Compiler/IBMClang.cmake6
-rw-r--r--Modules/Compiler/Intel.cmake14
-rw-r--r--Modules/Compiler/IntelLLVM-C.cmake6
-rw-r--r--Modules/Compiler/IntelLLVM-CXX.cmake18
-rw-r--r--Modules/Compiler/IntelLLVM.cmake20
-rw-r--r--Modules/Compiler/LCC-C-DetermineCompiler.cmake6
-rw-r--r--Modules/Compiler/LCC-CXX-DetermineCompiler.cmake6
-rw-r--r--Modules/Compiler/LCC.cmake14
-rw-r--r--Modules/Compiler/LLVMFlang-Fortran.cmake1
-rw-r--r--Modules/Compiler/NAG-Fortran.cmake4
-rw-r--r--Modules/Compiler/NVIDIA-CUDA.cmake2
-rw-r--r--Modules/Compiler/QCC.cmake14
-rw-r--r--Modules/Compiler/Tasking.cmake14
-rw-r--r--Modules/ExternalData.cmake2
-rw-r--r--Modules/ExternalProject.cmake46
-rw-r--r--Modules/FetchContent.cmake18
-rw-r--r--Modules/FindBZip2.cmake21
-rw-r--r--Modules/FindCUDAToolkit.cmake116
-rw-r--r--Modules/FindHDF5.cmake4
-rw-r--r--Modules/FindImageMagick.cmake123
-rw-r--r--Modules/FindLibLZMA.cmake20
-rw-r--r--Modules/FindMFC.cmake6
-rw-r--r--Modules/FindMPI.cmake18
-rw-r--r--Modules/FindMatlab.cmake51
-rw-r--r--Modules/FindMsys.cmake9
-rw-r--r--Modules/FindOpenCL.cmake2
-rw-r--r--Modules/FindOpenMP.cmake33
-rw-r--r--Modules/FindOpenSSL.cmake71
-rw-r--r--Modules/FindPython.cmake83
-rw-r--r--Modules/FindPython/Support.cmake796
-rw-r--r--Modules/FindPython2.cmake4
-rw-r--r--Modules/FindPython3.cmake79
-rw-r--r--Modules/FindQt4.cmake2
-rw-r--r--Modules/FindThreads.cmake12
-rw-r--r--Modules/FindUnixCommands.cmake4
-rw-r--r--Modules/FindZLIB.cmake75
-rw-r--r--Modules/FindwxWidgets.cmake2
-rw-r--r--Modules/FindwxWindows.cmake2
-rw-r--r--Modules/FortranCInterface.cmake4
-rw-r--r--Modules/FortranCInterface/Detect.cmake6
-rw-r--r--Modules/GoogleTest.cmake8
-rw-r--r--Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake5
-rw-r--r--Modules/Internal/CPack/CPackRPM.cmake4
-rw-r--r--Modules/Internal/CheckFlagCommonConfig.cmake12
-rw-r--r--Modules/Internal/CheckSourceCompiles.cmake19
-rw-r--r--Modules/Internal/CheckSourceRuns.cmake18
-rw-r--r--Modules/Internal/FeatureTesting.cmake17
-rw-r--r--Modules/Platform/Android-Clang.cmake4
-rw-r--r--Modules/Platform/Android-Determine.cmake4
-rw-r--r--Modules/Platform/CYGWIN.cmake45
-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.cmake11
-rw-r--r--Modules/Platform/Linux-OpenWatcom.cmake14
-rw-r--r--Modules/Platform/OS2-OpenWatcom.cmake22
-rw-r--r--Modules/Platform/Windows-OpenWatcom.cmake14
-rw-r--r--Modules/Platform/Windows3x-OpenWatcom-C.cmake2
-rw-r--r--Modules/Platform/Windows3x-OpenWatcom-CXX.cmake2
-rw-r--r--Modules/Platform/Windows3x-OpenWatcom.cmake33
-rw-r--r--Modules/Platform/Windows3x.cmake12
-rw-r--r--Modules/ProcessorCount.cmake12
-rw-r--r--Modules/SystemInformation.cmake6
-rw-r--r--Modules/TestBigEndian.cmake7
-rw-r--r--Modules/TestCXXAcceptsFlag.cmake8
-rw-r--r--Modules/TestForANSIForScope.cmake8
-rw-r--r--Modules/TestForANSIStreamHeaders.cxx2
-rw-r--r--Modules/TestForAnsiForScope.cxx2
-rw-r--r--Modules/TestForSSTREAM.cmake8
-rw-r--r--Modules/TestForSSTREAM.cxx2
-rw-r--r--Modules/TestForSTDNamespace.cmake8
-rw-r--r--Modules/TestForSTDNamespace.cxx2
-rw-r--r--Modules/UseJava.cmake2
-rw-r--r--Modules/UseSWIG.cmake69
-rw-r--r--Modules/UsewxWidgets.cmake29
-rw-r--r--Modules/WriteBasicConfigVersionFile.cmake15
-rw-r--r--Source/.gitattributes2
-rw-r--r--Source/CMakeLists.txt7
-rw-r--r--Source/CMakeVersion.cmake6
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx2
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx38
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.cxx6
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx8
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx8
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx6
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx2
-rw-r--r--Source/CPack/cmCPackExternalGenerator.cxx4
-rw-r--r--Source/CPack/cmCPackGenerator.cxx36
-rw-r--r--Source/CPack/cmCPackGenerator.h10
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx2
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx17
-rw-r--r--Source/CPack/cpack.cxx190
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx2
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx16
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx7
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx1
-rw-r--r--Source/CTest/cmCTestCurl.cxx8
-rw-r--r--Source/CTest/cmCTestGenericHandler.cxx16
-rw-r--r--Source/CTest/cmCTestGenericHandler.h12
-rw-r--r--Source/CTest/cmCTestHandlerCommand.cxx4
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx4
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx4
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx19
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx4
-rw-r--r--Source/Checks/Curses/CMakeLists.txt5
-rw-r--r--Source/CursesDialog/ccmake.cxx40
-rw-r--r--Source/CursesDialog/form/.gitattributes2
-rw-r--r--Source/QtDialog/CMakeSetup.cxx37
-rw-r--r--Source/QtDialog/CMakeSetupDialog.cxx3
-rw-r--r--Source/QtDialog/EnvironmentDialog.cxx14
-rw-r--r--Source/QtDialog/QCMakeCacheView.cxx8
-rw-r--r--Source/QtDialog/QCMakeCacheView.h7
-rw-r--r--Source/QtDialog/QCMakeWidgets.cxx34
-rw-r--r--Source/QtDialog/QCMakeWidgets.h8
-rw-r--r--Source/cmArchiveWrite.cxx2
-rw-r--r--Source/cmBinUtilsLinuxELFLinker.cxx9
-rw-r--r--Source/cmCMakePresetsGraphInternal.h2
-rw-r--r--Source/cmCMakePresetsGraphReadJSON.cxx4
-rw-r--r--Source/cmCPluginAPI.h4
-rw-r--r--Source/cmCTest.cxx86
-rw-r--r--Source/cmCTest.h2
-rw-r--r--Source/cmCallVisualStudioMacro.h3
-rw-r--r--Source/cmCommandLineArgument.h11
-rw-r--r--Source/cmCommonTargetGenerator.cxx7
-rw-r--r--Source/cmCommonTargetGenerator.h2
-rw-r--r--Source/cmComputeComponentGraph.cxx33
-rw-r--r--Source/cmComputeComponentGraph.h25
-rw-r--r--Source/cmComputeLinkDepends.cxx128
-rw-r--r--Source/cmComputeLinkDepends.h60
-rw-r--r--Source/cmComputeLinkInformation.cxx12
-rw-r--r--Source/cmComputeTargetDepends.cxx115
-rw-r--r--Source/cmComputeTargetDepends.h31
-rw-r--r--Source/cmConfigureLog.cxx303
-rw-r--r--Source/cmConfigureLog.h72
-rw-r--r--Source/cmCoreTryCompile.cxx146
-rw-r--r--Source/cmCoreTryCompile.h25
-rw-r--r--Source/cmCustomCommandGenerator.cxx27
-rw-r--r--Source/cmCustomCommandGenerator.h2
-rw-r--r--Source/cmCxxModuleMapper.cxx36
-rw-r--r--Source/cmCxxModuleMapper.h1
-rw-r--r--Source/cmDependsFortran.cxx18
-rw-r--r--Source/cmDependsFortran.h2
-rw-r--r--Source/cmDocumentation.cxx169
-rw-r--r--Source/cmDocumentation.h57
-rw-r--r--Source/cmDocumentationEntry.h29
-rw-r--r--Source/cmDocumentationFormatter.cxx234
-rw-r--r--Source/cmDocumentationFormatter.h56
-rw-r--r--Source/cmDocumentationSection.cxx28
-rw-r--r--Source/cmDocumentationSection.h22
-rw-r--r--Source/cmDyndepCollation.cxx652
-rw-r--r--Source/cmDyndepCollation.h52
-rw-r--r--Source/cmExperimental.cxx2
-rw-r--r--Source/cmExportFileGenerator.cxx13
-rw-r--r--Source/cmExportInstallFileGenerator.cxx4
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx2
-rw-r--r--Source/cmExtraEclipseCDT4Generator.cxx2
-rw-r--r--Source/cmFileAPI.cxx96
-rw-r--r--Source/cmFileAPI.h8
-rw-r--r--Source/cmFileAPICodemodel.cxx112
-rw-r--r--Source/cmFileAPIConfigureLog.cxx68
-rw-r--r--Source/cmFileAPIConfigureLog.h12
-rw-r--r--Source/cmFileCommand.cxx87
-rw-r--r--Source/cmFileLockPool.cxx4
-rw-r--r--Source/cmFileSet.cxx9
-rw-r--r--Source/cmFileSet.h4
-rw-r--r--Source/cmFindBase.cxx2
-rw-r--r--Source/cmFindPackageCommand.cxx16
-rw-r--r--Source/cmGeneratedFileStream.cxx11
-rw-r--r--Source/cmGeneratorExpression.cxx80
-rw-r--r--Source/cmGeneratorExpression.h13
-rw-r--r--Source/cmGeneratorExpressionEvaluationFile.cxx2
-rw-r--r--Source/cmGeneratorExpressionEvaluator.cxx31
-rw-r--r--Source/cmGeneratorExpressionNode.cxx42
-rw-r--r--Source/cmGeneratorTarget.cxx401
-rw-r--r--Source/cmGeneratorTarget.h60
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx7
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx7
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h3
-rw-r--r--Source/cmGlobalCommonGenerator.cxx24
-rw-r--r--Source/cmGlobalCommonGenerator.h13
-rw-r--r--Source/cmGlobalGenerator.cxx64
-rw-r--r--Source/cmGlobalGenerator.h6
-rw-r--r--Source/cmGlobalGeneratorFactory.h23
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx16
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h3
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx8
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h3
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.cxx8
-rw-r--r--Source/cmGlobalMSYSMakefileGenerator.h9
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.cxx8
-rw-r--r--Source/cmGlobalMinGWMakefileGenerator.h5
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx16
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h3
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx548
-rw-r--r--Source/cmGlobalNinjaGenerator.h24
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx19
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h6
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx130
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h16
-rw-r--r--Source/cmGlobalVisualStudio11Generator.cxx30
-rw-r--r--Source/cmGlobalVisualStudio11Generator.h3
-rw-r--r--Source/cmGlobalVisualStudio12Generator.cxx17
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx17
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx19
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx71
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h8
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx52
-rw-r--r--Source/cmGlobalVisualStudio9Generator.cxx11
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx19
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h7
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx81
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.h11
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx8
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h3
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx76
-rw-r--r--Source/cmGlobalXCodeGenerator.h8
-rw-r--r--Source/cmGraphAdjacencyList.h9
-rw-r--r--Source/cmIDEOptions.cxx15
-rw-r--r--Source/cmInstalledFile.cxx4
-rw-r--r--Source/cmJSONHelpers.h28
-rw-r--r--Source/cmLinkLineComputer.cxx10
-rw-r--r--Source/cmLocalGenerator.cxx81
-rw-r--r--Source/cmLocalGenerator.h4
-rw-r--r--Source/cmLocalNinjaGenerator.cxx2
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx6
-rw-r--r--Source/cmLocalVisualStudio10Generator.cxx12
-rw-r--r--Source/cmLocalVisualStudio10Generator.h2
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx109
-rw-r--r--Source/cmLocalVisualStudio7Generator.h4
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx8
-rw-r--r--Source/cmLocalVisualStudioGenerator.h4
-rw-r--r--Source/cmLocalXCodeGenerator.cxx2
-rw-r--r--Source/cmMakefile.cxx36
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx5
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx7
-rw-r--r--Source/cmMakefileProfilingData.cxx57
-rw-r--r--Source/cmMakefileProfilingData.h30
-rw-r--r--Source/cmMakefileTargetGenerator.cxx48
-rw-r--r--Source/cmMakefileTargetGenerator.h1
-rw-r--r--Source/cmMessageCommand.cxx26
-rw-r--r--Source/cmMessenger.cxx4
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx113
-rw-r--r--Source/cmNinjaTargetGenerator.cxx441
-rw-r--r--Source/cmNinjaTargetGenerator.h21
-rw-r--r--Source/cmOutputConverter.cxx20
-rw-r--r--Source/cmOutputConverter.h7
-rw-r--r--Source/cmPolicies.h5
-rw-r--r--Source/cmProjectCommand.cxx9
-rw-r--r--Source/cmQtAutoGenInitializer.cxx5
-rw-r--r--Source/cmQtAutoMocUic.cxx5
-rw-r--r--Source/cmRange.h6
-rw-r--r--Source/cmRulePlaceholderExpander.cxx5
-rw-r--r--Source/cmRulePlaceholderExpander.h2
-rw-r--r--Source/cmSearchPath.cxx15
-rw-r--r--Source/cmSetPropertyCommand.cxx7
-rw-r--r--Source/cmState.cxx2
-rw-r--r--Source/cmState.h1
-rw-r--r--Source/cmStateSnapshot.cxx8
-rw-r--r--Source/cmStringAlgorithms.cxx44
-rw-r--r--Source/cmStringAlgorithms.h42
-rw-r--r--Source/cmStringCommand.cxx64
-rw-r--r--Source/cmSystemTools.cxx46
-rw-r--r--Source/cmSystemTools.h8
-rw-r--r--Source/cmTarget.cxx969
-rw-r--r--Source/cmTargetIncludeDirectoriesCommand.cxx5
-rw-r--r--Source/cmTargetPropCommandBase.cxx2
-rw-r--r--Source/cmTargetPropCommandBase.h7
-rw-r--r--Source/cmTestGenerator.cxx3
-rw-r--r--Source/cmTimestamp.cxx63
-rw-r--r--Source/cmTimestamp.h4
-rw-r--r--Source/cmTryCompileCommand.cxx31
-rw-r--r--Source/cmTryRunCommand.cxx120
-rw-r--r--Source/cmUVProcessChain.cxx1
-rw-r--r--Source/cmVSSetupHelper.cxx93
-rw-r--r--Source/cmVSSetupHelper.h27
-rw-r--r--Source/cmVersionConfig.h.in2
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx291
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h13
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx41
-rw-r--r--Source/cmVisualStudioGeneratorOptions.h1
-rw-r--r--Source/cmVisualStudioSlnData.cxx43
-rw-r--r--Source/cmVisualStudioSlnData.h16
-rw-r--r--Source/cmVisualStudioSlnParser.cxx189
-rw-r--r--Source/cmVisualStudioSlnParser.h4
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.cxx9
-rw-r--r--Source/cmVisualStudioWCEPlatformParser.h11
-rw-r--r--Source/cmake.cxx329
-rw-r--r--Source/cmake.h90
-rw-r--r--Source/cmakemain.cxx69
-rw-r--r--Source/cmcmd.cxx74
-rw-r--r--Source/ctest.cxx30
-rw-r--r--Source/kwsys/CONTRIBUTING.rst2
-rw-r--r--Source/kwsys/CommandLineArguments.cxx2
-rw-r--r--Source/kwsys/Glob.cxx4
-rw-r--r--Source/kwsys/ProcessUNIX.c13
-rw-r--r--Source/kwsys/ProcessWin32.c5
-rw-r--r--Source/kwsys/RegularExpression.cxx56
-rw-r--r--Source/kwsys/RegularExpression.hxx.in10
-rw-r--r--Source/kwsys/Status.hxx.in10
-rw-r--r--Source/kwsys/SystemInformation.cxx6
-rw-r--r--Source/kwsys/SystemTools.cxx100
-rw-r--r--Source/kwsys/SystemTools.hxx.in44
-rw-r--r--Source/kwsys/kwsysPrivate.h2
-rw-r--r--Source/kwsys/testConfigure.cxx2
-rw-r--r--Source/kwsys/testConsoleBuf.cxx2
-rw-r--r--Source/kwsys/testDirectory.cxx11
-rw-r--r--Source/kwsys/testEncoding.cxx2
-rw-r--r--Source/kwsys/testFStream.cxx2
-rw-r--r--Source/kwsys/testStatus.cxx2
-rw-r--r--Source/kwsys/testSystemInformation.cxx2
-rw-r--r--Source/kwsys/testSystemTools.cxx2
-rw-r--r--Templates/MSBuild/FlagTables/v10_MARMASM.json140
-rw-r--r--Templates/MSBuild/FlagTables/v142_CL.json7
-rw-r--r--Templates/MSBuild/FlagTables/v143_CL.json7
-rw-r--r--Templates/MSBuild/nasm.targets2
-rw-r--r--Tests/CMakeCommands/target_include_directories/CMakeLists.txt5
-rw-r--r--Tests/CMakeCommands/target_include_directories/same.c7
-rw-r--r--Tests/CMakeCommands/target_include_directories/same_one/same.h1
-rw-r--r--Tests/CMakeCommands/target_include_directories/same_two/same.h1
-rw-r--r--Tests/CMakeGUI/CatchShow.h13
-rw-r--r--Tests/CMakeLib/testArgumentParser.cxx2
-rw-r--r--Tests/CMakeLib/testCMExtAlgorithm.cxx2
-rw-r--r--Tests/CMakeLib/testCMExtEnumSet.cxx2
-rw-r--r--Tests/CMakeLib/testCMExtMemory.cxx2
-rw-r--r--Tests/CMakeLib/testCMFilesystemPath.cxx2
-rw-r--r--Tests/CMakeLib/testCTestBinPacker.cxx2
-rw-r--r--Tests/CMakeLib/testCTestResourceGroups.cxx2
-rw-r--r--Tests/CMakeLib/testFindPackageCommand.cxx2
-rw-r--r--Tests/CMakeLib/testGeneratedFileStream.cxx2
-rw-r--r--Tests/CMakeLib/testJSONHelpers.cxx2
-rw-r--r--Tests/CMakeLib/testOptional.cxx2
-rw-r--r--Tests/CMakeLib/testRange.cxx2
-rw-r--r--Tests/CMakeLib/testString.cxx2
-rw-r--r--Tests/CMakeLib/testStringAlgorithms.cxx26
-rw-r--r--Tests/CMakeLib/testSystemTools.cxx2
-rw-r--r--Tests/CMakeLib/testUTF8.cxx2
-rw-r--r--Tests/CMakeLib/testUVRAII.cxx3
-rw-r--r--Tests/CMakeLib/testUVStreambuf.cxx13
-rw-r--r--Tests/CMakeLib/testVisualStudioSlnParser.cxx2
-rw-r--r--Tests/CMakeLib/testXMLParser.cxx2
-rw-r--r--Tests/CMakeLib/testXMLSafe.cxx2
-rw-r--r--Tests/CMakeLists.txt70
-rw-r--r--Tests/CMakeOnly/AllFindModules/CMakeLists.txt4
-rw-r--r--Tests/CMakeTests/CMakeLists.txt10
-rw-r--r--Tests/CMakeTests/FileDownloadBadHashTest.cmake.in13
-rw-r--r--Tests/CMakeTests/FileDownloadTest.cmake.in229
-rw-r--r--Tests/CMakeTests/FileUploadInput.png (renamed from Tests/CMakeTests/FileDownloadInput.png)bin194 -> 194 bytes
-rw-r--r--Tests/CMakeTests/FileUploadTest.cmake.in2
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake22
-rw-r--r--Tests/CMakeTests/StringTest.cmake.in3
-rw-r--r--Tests/CSharpLinkFromCxx/.gitattributes2
-rw-r--r--Tests/CheckFortran.cmake1
-rw-r--r--Tests/CheckSourceTree/check.cmake9
-rw-r--r--Tests/CheckSwift.cmake1
-rw-r--r--Tests/CompileFeatures/.gitattributes2
-rw-r--r--Tests/CompileFeatures/CMakeLists.txt13
-rw-r--r--Tests/CompileFeatures/cxx_attribute_deprecated.cpp5
-rw-r--r--Tests/CompileFeatures/cxx_attributes.cpp2
-rw-r--r--Tests/CompileFeatures/msvc_permissive.cxx9
-rw-r--r--Tests/Cuda/CMakeLists.txt7
-rw-r--r--Tests/Cuda/SeparableCompCXXOnly/main.cpp2
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt11
-rw-r--r--Tests/Cuda/SharedRuntimePlusToolkit/main.cpp17
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt26
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp8
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/main.cpp27
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp14
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp8
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp10
-rw-r--r--Tests/Cuda/StaticRuntimePlusToolkit/static.cpp14
-rw-r--r--Tests/Cuda/Toolkit/CMakeLists.txt8
-rw-r--r--Tests/CudaOnly/CMakeLists.txt7
-rw-r--r--Tests/CudaOnly/SeparateCompilation/CMakeLists.txt26
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file1.h9
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file4.cu2
-rw-r--r--Tests/CudaOnly/SeparateCompilation/file5.cu2
-rw-r--r--Tests/CudaOnly/SeparateCompilation/main/CMakeLists.txt2
-rw-r--r--Tests/CudaOnly/SeparateCompilation/main/main.cu4
-rw-r--r--Tests/CudaOnly/SeparateCompilationPTX/main.cu9
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt10
-rw-r--r--Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu17
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt24
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu8
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu27
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu14
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu8
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu10
-rw-r--r--Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu14
-rw-r--r--Tests/CudaOnly/Toolkit/CMakeLists.txt10
-rw-r--r--Tests/CustomCommandByproducts/CMakeLists.txt35
-rw-r--r--Tests/CustomCommandByproducts/ExternalLibraryByproducts.c5
-rw-r--r--Tests/FindImageMagick/CMakeLists.txt10
-rw-r--r--Tests/FindImageMagick/Test/CMakeLists.txt13
-rw-r--r--Tests/FindImageMagick/Test/main_magick++.cxx10
-rw-r--r--Tests/FindImageMagick/Test/main_magick_wand.c8
-rw-r--r--Tests/FindOpenACC/CXXTest/main.cxx2
-rw-r--r--Tests/FindPython/CMakeLists.txt30
-rw-r--r--Tests/FindPython/Python2SABIModule/CMakeLists.txt5
-rw-r--r--Tests/FindPython/Python3Module/CMakeLists.txt9
-rw-r--r--Tests/FindPython/Python3SABIModule/CMakeLists.txt51
-rw-r--r--Tests/FindPython/RequiredArtifacts/CMakeLists.txt32
-rw-r--r--Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt8
-rw-r--r--Tests/FortranOnly/CMakeLists.txt22
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt22
-rw-r--r--Tests/GeneratorExpression/check-part3.cmake1
-rw-r--r--Tests/GeneratorExpression/check-part4.cmake9
-rw-r--r--Tests/PositionIndependentTargets/.gitattributes2
-rw-r--r--Tests/QtAutogen/Complex/calwidget.cpp2
-rw-r--r--Tests/RunCMake/AutoExportDll/AutoExport.cmake4
-rw-r--r--Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/CMakeLists.txt94
-rw-r--r--Tests/RunCMake/CMakePresets/NoDebug-stdout.txt4
-rw-r--r--Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake11
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_bad-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt)0
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_bad-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_empty_legacy-stderr.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_error-result.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/no-tests_env_error-stderr.txt1
-rw-r--r--Tests/RunCMake/CXXModules/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterfaceImported.cmake2
-rw-r--r--Tests/RunCMake/CXXModules/FileSetModulesInterfaceImported.cmake2
-rw-r--r--Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt5
-rw-r--r--Tests/RunCMake/CXXModules/RunCMakeTest.cmake35
-rw-r--r--Tests/RunCMake/CXXModules/compiler_introspection.cmake1
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular-build-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt)0
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt1
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular-stderr.txt9
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt15
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm6
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm6
-rw-r--r--Tests/RunCMake/CXXModules/examples/cxx-modules-find-bmi.cmake2
-rw-r--r--Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake2
-rw-r--r--Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt9
-rw-r--r--Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt39
-rw-r--r--Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx11
-rw-r--r--Tests/RunCMake/CXXModules/examples/duplicate/main.cxx6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/test/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/test/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-build/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt12
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-install/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt12
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-stderr.txt9
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/CMakeLists.txt53
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx10
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/test/CMakeLists.txt32
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-stderr.txt9
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/CMakeLists.txt56
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx10
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx6
-rw-r--r--Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/test/CMakeLists.txt32
-rw-r--r--Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/partitions/importable.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/partitions/partition.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties-stderr.txt9
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt61
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/always_scan.cxx12
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/join.cxx19
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/main.cxx18
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/module.cxx12
-rw-r--r--Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx10
-rw-r--r--Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/sources/module-internal-part.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/sources/module-part-impl.cxx4
-rw-r--r--Tests/RunCMake/CXXModules/sources/module-part.cxx2
-rw-r--r--Tests/RunCMake/CXXModules/sources/module.cxx4
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake21
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake15
-rw-r--r--Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake35
-rw-r--r--Tests/RunCMake/ClangTidy/ExportFixesDir.cmake6
-rw-r--r--Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake35
-rw-r--r--Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake35
-rw-r--r--Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake6
-rw-r--r--Tests/RunCMake/ClangTidy/RunCMakeTest.cmake52
-rw-r--r--Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/ClangTidy/extra.c3
-rw-r--r--Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake3
-rw-r--r--Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake1
-rw-r--r--Tests/RunCMake/CommandLine/E_capabilities-stdout.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt)0
-rw-r--r--Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt2
-rw-r--r--Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/P_P_in_arbitrary_args-stdout.txt10
-rw-r--r--Tests/RunCMake/CommandLine/P_P_in_arbitrary_args_2-stdout.txt10
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake29
-rw-r--r--Tests/RunCMake/CommandLine/build-no-dir2-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt)0
-rw-r--r--Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/.gitattributes2
-rw-r--r--Tests/RunCMake/CommandLine/cmake_depends/test.c1
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/.gitattributes4
-rw-r--r--Tests/RunCMake/CommandLine/compare_files/crlf2
-rw-r--r--Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake13
-rw-r--r--Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt4
-rw-r--r--Tests/RunCMake/CommandLine/trace-try_compile.cmake2
-rw-r--r--Tests/RunCMake/CompileDefinitions/RemoveLeadingMinusD.cmake11
-rw-r--r--Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/CompileDefinitions/foo.c4
-rw-r--r--Tests/RunCMake/Configure/CopyFileABI-stdout.txt4
-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/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake14
-rw-r--r--Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake9
-rw-r--r--Tests/RunCMake/ExportImport/RunCMakeTest.cmake25
-rw-r--r--Tests/RunCMake/ExportImport/buildlib.c8
-rw-r--r--Tests/RunCMake/ExportImport/installlib.c8
-rw-r--r--Tests/RunCMake/ExportImport/locallib.c8
-rw-r--r--Tests/RunCMake/FileAPI/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-check.py31
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_1.json31
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_2.json9
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json5
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json6
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json2
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json3
-rw-r--r--Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json3
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-prep.cmake4
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-check.cmake11
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-check.cmake10
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-prep.cmake2
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1-check.py21
-rw-r--r--Tests/RunCMake/FileAPI/configureLog-v1.cmake1
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt2
-rw-r--r--Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt2
-rw-r--r--Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake3
-rw-r--r--Tests/RunCMake/FindBoost/CommonNotFound.cmake4
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake40
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake21
-rw-r--r--Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL-check.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL-check.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName.cmake)4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName1/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName1/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName2/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName2/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName3/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName3/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName4/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName4/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName5/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName5/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName6/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName6/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName7/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName7/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName8/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName8/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt)2
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget.cmake9
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference.cmake)4
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference1/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference2/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference3/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference4/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference5/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference6/CMakeLists.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6/CMakeLists.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES-check.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION-stderr.txt (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-result.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-result.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-stderr.txt (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-stderr.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6.cmake)5
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake)15
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES-check.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES.cmake (renamed from Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES.cmake)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt6
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c12
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake19
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt15
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt10
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.c (renamed from Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.cpp (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/empty.cpp)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.c (renamed from Tests/RunCMake/GeneratorExpression/empty2.c)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.c (renamed from Tests/RunCMake/GeneratorExpression/empty3.c)0
-rw-r--r--Tests/RunCMake/GenEx-TARGET_PROPERTY/main.cpp (renamed from Tests/RunCMake/TargetPropertyGeneratorExpressions/main.cpp)0
-rw-r--r--Tests/RunCMake/GenerateExportHeader/reference/.gitattributes2
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt9
-rw-r--r--Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake1
-rw-r--r--Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/GeneratorInstance/DefaultInstance-stdout.txt1
-rw-r--r--Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake2
-rw-r--r--Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake4
-rw-r--r--Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt5
-rw-r--r--Tests/RunCMake/GoogleTest/GoogleTest.cmake4
-rw-r--r--Tests/RunCMake/GoogleTest/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/GoogleTest/skip_test.cpp7
-rw-r--r--Tests/RunCMake/Ninja/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-English-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-English-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-English.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-French-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-French-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-French.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-German-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-German-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-German.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-Italian-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-Italian-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-437-Italian.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-check.cmake (renamed from Tests/RunCMake/Ninja/ShowIncludes-54936-check.cmake)2
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese.cmake (renamed from Tests/RunCMake/Ninja/ShowIncludes-54936.cmake)1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-54936-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-check.cmake (renamed from Tests/RunCMake/Ninja/ShowIncludes-65001-check.cmake)2
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese.cmake (renamed from Tests/RunCMake/Ninja/ShowIncludes-65001.cmake)1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-French-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-French-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-French.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-65001-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-check.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-stdout.txt1
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-932-Japanese.cmake3
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes-cmake.cmake4
-rw-r--r--Tests/RunCMake/Ninja/ShowIncludes.cmake2
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake6
-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/RunCMake.cmake67
-rw-r--r--Tests/RunCMake/RunCTest.cmake5
-rw-r--r--Tests/RunCMake/Swift/IncrementalSwift-second-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt)0
-rw-r--r--Tests/RunCMake/Swift/IncrementalSwift-second-stderr.txt2
-rw-r--r--Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt3
-rw-r--r--Tests/RunCMake/Swift/IncrementalSwift.cmake22
-rw-r--r--Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt1
-rw-r--r--Tests/RunCMake/Swift/NoWorkToDo.cmake5
-rw-r--r--Tests/RunCMake/Swift/RunCMakeTest.cmake31
-rw-r--r--Tests/RunCMake/Swift/hello.swift (renamed from Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt)0
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget.cmake7
-rw-r--r--Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt8
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsCLREmpty.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRNetcore.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRPure-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRPure.cmake6
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake24
-rw-r--r--Tests/RunCMake/VS10Project/VsCLRSafe.cmake6
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-NEW-check.cmake6
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-NEW.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-OLD-check.cmake6
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-OLD.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-WARN-check.cmake6
-rw-r--r--Tests/RunCMake/VSSolution/CMP0143-WARN.cmake1
-rw-r--r--Tests/RunCMake/VSSolution/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/VsDotnetSdk/App.xaml9
-rw-r--r--Tests/RunCMake/VsDotnetSdk/App.xaml.cs17
-rw-r--r--Tests/RunCMake/VsDotnetSdk/MainWindow.xaml12
-rw-r--r--Tests/RunCMake/VsDotnetSdk/MainWindow.xaml.cs28
-rw-r--r--Tests/RunCMake/VsDotnetSdk/Resources.Designer.cs63
-rw-r--r--Tests/RunCMake/VsDotnetSdk/Resources.resx117
-rw-r--r--Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles-check.cmake56
-rw-r--r--Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles.cmake48
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS-check.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS-check.cmake4
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions.cmake22
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/ExtensionKit.Info.plist.in13
-rw-r--r--Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake27
-rw-r--r--Tests/RunCMake/XcodeProject/InheritedParameters-check.cmake24
-rw-r--r--Tests/RunCMake/XcodeProject/InheritedParameters.cmake5
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/add_compile_definitions/CMakeLists.txt5
-rw-r--r--Tests/RunCMake/add_compile_definitions/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/add_compile_definitions/foo.c4
-rw-r--r--Tests/RunCMake/add_compile_definitions/remove_leading_minusD.cmake6
-rw-r--r--Tests/RunCMake/add_custom_command/CommentGenex-build-stdout.txt1
-rw-r--r--Tests/RunCMake/add_custom_command/CommentGenex.cmake9
-rw-r--r--Tests/RunCMake/add_custom_command/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/add_custom_target/CommentGenex-build-stdout.txt1
-rw-r--r--Tests/RunCMake/add_custom_target/CommentGenex.cmake6
-rw-r--r--Tests/RunCMake/add_custom_target/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt4
-rw-r--r--Tests/RunCMake/configure_file/RerunCMake-stdout.txt4
-rw-r--r--Tests/RunCMake/ctest_environment/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/ctest_test/RunCMakeTest.cmake3
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt8
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake13
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake31
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt2
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake3
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad.cmake6
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good.cmake6
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake9
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/basic.cmake3
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/common.cmake15
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake10
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/hash-mismatch-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt11
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake8
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-result.txt (renamed from Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-stderr.txt (renamed from Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt)2
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/httpheader-not-set.cmake (renamed from Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/input.pngbin0 -> 194 bytes
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/netrc-bad-result.txt (renamed from Tests/RunCMake/Configure/ErrorLogs-result.txt)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/netrc-bad-stderr.txt (renamed from Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt)8
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/netrc-bad.cmake (renamed from Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake)4
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/netrc-bad.txt (renamed from Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake11
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-file.cmake11
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt1
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-save-hash-stderr.txt (renamed from Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt)3
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake5
-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.txt (renamed from Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt)2
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/pass-not-set.cmake (renamed from Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/range-stdout.txt4
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/range.cmake15
-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.txt (renamed from Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt)2
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set.cmake (renamed from Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake)0
-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.txt (renamed from Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt)2
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set.cmake (renamed from Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake)0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt0
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/unused-argument-stderr.txt (renamed from Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt)3
-rw-r--r--Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake3
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-parent-rpath-propagation.cmake54
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/main.c12
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/one.c7
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/three.c3
-rw-r--r--Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/two.c6
-rw-r--r--Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake10
-rw-r--r--Tests/RunCMake/file/COPY_FILE-input-missing-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-input-missing-stderr.txt14
-rw-r--r--Tests/RunCMake/file/COPY_FILE-input-missing.cmake3
-rw-r--r--Tests/RunCMake/file/COPY_FILE-output-missing-result.txt1
-rw-r--r--Tests/RunCMake/file/COPY_FILE-output-missing-stderr.txt14
-rw-r--r--Tests/RunCMake/file/COPY_FILE-output-missing.cmake4
-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-no-save-hash.cmake8
-rw-r--r--Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake8
-rw-r--r--Tests/RunCMake/file/MAKE_DIRECTORY-fail-result.txt1
-rw-r--r--Tests/RunCMake/file/MAKE_DIRECTORY-fail-stderr.txt9
-rw-r--r--Tests/RunCMake/file/MAKE_DIRECTORY-fail.cmake2
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/find_dependency/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/find_dependency/transitive-stdout.txt9
-rw-r--r--Tests/RunCMake/find_dependency/transitive.cmake3
-rw-r--r--Tests/RunCMake/find_dependency/transitive/AConfig.cmake1
-rw-r--r--Tests/RunCMake/find_dependency/transitive/BConfig.cmake3
-rw-r--r--Tests/RunCMake/find_dependency/transitive/CConfig.cmake3
-rw-r--r--Tests/RunCMake/find_dependency/transitive/DConfig.cmake5
-rw-r--r--Tests/RunCMake/find_dependency/transitive/EConfig.cmake6
-rw-r--r--Tests/RunCMake/if/IsDirectoryLong.cmake3
-rw-r--r--Tests/RunCMake/if/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/if/exists.cmake3
-rw-r--r--Tests/RunCMake/message/ConfigureLog-config.txt30
-rw-r--r--Tests/RunCMake/message/ConfigureLog-stdout.txt4
-rw-r--r--Tests/RunCMake/message/ConfigureLog.cmake7
-rw-r--r--Tests/RunCMake/message/ConfigureLogScript-config.txt1
-rw-r--r--Tests/RunCMake/message/ConfigureLogScript-stdout.txt4
-rw-r--r--Tests/RunCMake/message/ConfigureLogScript.cmake1
-rw-r--r--Tests/RunCMake/message/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt2
-rw-r--r--Tests/RunCMake/project/CMP0048-OLD-stderr.txt2
-rw-r--r--Tests/RunCMake/project/CMP0048-WARN-stderr.txt2
-rw-r--r--Tests/RunCMake/project/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/project/LanguagesTwice-stderr.txt2
-rw-r--r--Tests/RunCMake/project/NoMinimumRequired-stderr.txt5
-rw-r--r--Tests/RunCMake/project/NoMinimumRequired.cmake0
-rw-r--r--Tests/RunCMake/project/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/project/VersionInvalid-stderr.txt2
-rw-r--r--Tests/RunCMake/project/VersionMissingLanguages-stderr.txt2
-rw-r--r--Tests/RunCMake/project/VersionTwice-stderr.txt2
-rw-r--r--Tests/RunCMake/project_injected/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/pseudo_tidy.c13
-rw-r--r--Tests/RunCMake/showIncludes.c83
-rw-r--r--Tests/RunCMake/string/Timestamp-stderr.txt2
-rw-r--r--Tests/RunCMake/string/Timestamp.cmake2
-rw-r--r--Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake13
-rw-r--r--Tests/RunCMake/target_compile_definitions/foo.c4
-rw-r--r--Tests/RunCMake/target_compile_definitions/remove_leading_minusD.cmake9
-rw-r--r--Tests/RunCMake/target_compile_options/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/target_compile_options/bad_keyword-result.txt1
-rw-r--r--Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt2
-rw-r--r--Tests/RunCMake/target_compile_options/bad_keyword.cmake5
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt10
-rw-r--r--Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake2
-rw-r--r--Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake2
-rw-r--r--Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake4
-rw-r--r--Tests/RunCMake/try_compile/CMP0128-common.cmake23
-rw-r--r--Tests/RunCMake/try_compile/ConfigureLog-bad.c1
-rw-r--r--Tests/RunCMake/try_compile/ConfigureLog-config.txt79
-rw-r--r--Tests/RunCMake/try_compile/ConfigureLog-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/ConfigureLog-test.c4
-rw-r--r--Tests/RunCMake/try_compile/ConfigureLog.cmake38
-rw-r--r--Tests/RunCMake/try_compile/EmptyValueArgs-stderr.txt8
-rw-r--r--Tests/RunCMake/try_compile/EmptyValueArgs.cmake3
-rw-r--r--Tests/RunCMake/try_compile/ISPCTargets-stderr.txt2
-rw-r--r--Tests/RunCMake/try_compile/Inspect-config.txt65
-rw-r--r--Tests/RunCMake/try_compile/Inspect.cmake27
-rw-r--r--Tests/RunCMake/try_compile/NoLogDescription-result.txt1
-rw-r--r--Tests/RunCMake/try_compile/NoLogDescription-stderr.txt7
-rw-r--r--Tests/RunCMake/try_compile/NoLogDescription.cmake4
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/RerunCMake-stdout.txt4
-rw-r--r--Tests/RunCMake/try_compile/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/try_compile/SourceFromBadName-config.txt11
-rw-r--r--Tests/RunCMake/try_compile/Verbose.c7
-rw-r--r--Tests/RunCMake/try_compile/Verbose.cmake15
-rw-r--r--Tests/RunCMake/try_compile/old_and_new_signature_tests.cmake1
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-bad.c1
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-config.txt134
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-stdout.txt4
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog-test.c9
-rw-r--r--Tests/RunCMake/try_run/ConfigureLog.cmake34
-rw-r--r--Tests/RunCMake/try_run/RunCMakeTest.cmake1
-rw-r--r--Tests/StringFileTest/StringFile.cxx2
-rw-r--r--Tests/SwiftMixLib/CMakeLists.txt3
-rw-r--r--Tests/SwiftMixLib/main.c3
-rw-r--r--Tests/SwiftOnly/CMakeLists.txt11
-rw-r--r--Tests/SwiftOnly/SwiftPlugin/CMakeLists.txt5
-rw-r--r--Tests/SwiftOnly/SwiftPlugin/main.swift4
-rw-r--r--Tests/SwiftOnly/SwiftPlugin/plugin.swift3
-rw-r--r--Tests/SystemInformation/CMakeLists.txt2
-rw-r--r--Tests/SystemInformation/DumpInformation.cxx6
-rw-r--r--Tests/UseSWIG/BasicPerl/CMakeLists.txt4
-rw-r--r--Tests/UseSWIG/CMakeLists.txt30
-rw-r--r--Tests/UseSWIG/LegacyPerl/CMakeLists.txt4
-rw-r--r--Tests/VSMARMASM/CMakeLists.txt6
-rw-r--r--Tests/VSMARMASM/foo.asm10
-rw-r--r--Tests/VSMARMASM/main.c5
-rw-r--r--Tests/VSMASM/CMakeLists.txt2
-rw-r--r--Tests/VSMASM/foo.asm6
-rw-r--r--Tests/VSNASM/CMakeLists.txt2
-rw-r--r--Tests/VSNASM/foo.asm6
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/.gitattributes2
-rw-r--r--Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h10
-rw-r--r--Tests/Wrapping/Wrap.c3
-rw-r--r--Utilities/.gitattributes6
-rw-r--r--Utilities/ClangTidyModule/CMakeLists.txt37
-rw-r--r--Utilities/ClangTidyModule/Module.cxx38
-rw-r--r--Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx52
-rw-r--r--Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h21
-rw-r--r--Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx180
-rw-r--r--Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h34
-rw-r--r--Utilities/ClangTidyModule/Tests/CMakeLists.txt18
-rw-r--r--Utilities/ClangTidyModule/Tests/RunClangTidy.cmake93
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt6
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx10
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx40
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt124
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx40
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class-stdout.txt18
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class.cxx63
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx42
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt52
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx42
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx81
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt155
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx81
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt25
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx5
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h8
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h10
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h6
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h9
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h5
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h4
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h6
-rw-r--r--Utilities/ClangTidyModule/UseBespokeEnumClassCheck.cxx35
-rw-r--r--Utilities/ClangTidyModule/UseBespokeEnumClassCheck.h21
-rw-r--r--Utilities/ClangTidyModule/UseCmstrlenCheck.cxx78
-rw-r--r--Utilities/ClangTidyModule/UseCmstrlenCheck.h21
-rw-r--r--Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx101
-rw-r--r--Utilities/ClangTidyModule/UseCmsysFstreamCheck.h24
-rw-r--r--Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx325
-rw-r--r--Utilities/ClangTidyModule/UsePragmaOnceCheck.h60
-rw-r--r--Utilities/Doxygen/CMakeLists.txt2
-rw-r--r--Utilities/IWYU/mapping.imp4
-rwxr-xr-xUtilities/Scripts/clang-format.bash16
-rwxr-xr-xUtilities/Scripts/update-curl.bash2
-rwxr-xr-xUtilities/Scripts/update-nghttp2.bash4
-rw-r--r--Utilities/Sphinx/CMakeLists.txt110
-rw-r--r--Utilities/Sphinx/cmake.py1
-rw-r--r--Utilities/Sphinx/conf.py.in2
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake86
-rw-r--r--Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake2
-rw-r--r--Utilities/cmcurl/CMakeLists.txt16
-rw-r--r--Utilities/cmcurl/include/curl/curl.h234
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h6
-rw-r--r--Utilities/cmcurl/include/curl/easy.h2
-rw-r--r--Utilities/cmcurl/include/curl/mprintf.h2
-rw-r--r--Utilities/cmcurl/include/curl/multi.h8
-rw-r--r--Utilities/cmcurl/include/curl/system.h22
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h194
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt28
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc6
-rw-r--r--Utilities/cmcurl/lib/altsvc.c16
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c9
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c19
-rw-r--r--Utilities/cmcurl/lib/base64.c197
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c71
-rw-r--r--Utilities/cmcurl/lib/cfilters.c502
-rw-r--r--Utilities/cmcurl/lib/cfilters.h315
-rw-r--r--Utilities/cmcurl/lib/connect.c459
-rw-r--r--Utilities/cmcurl/lib/connect.h16
-rw-r--r--Utilities/cmcurl/lib/cookie.c26
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c5
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake12
-rw-r--r--Utilities/cmcurl/lib/curl_endian.h9
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.c7
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.c30
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c9
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c2
-rw-r--r--Utilities/cmcurl/lib/curl_path.c14
-rw-r--r--Utilities/cmcurl/lib/curl_range.c4
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c12
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c11
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h10
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h5
-rw-r--r--Utilities/cmcurl/lib/curl_sha256.h2
-rw-r--r--Utilities/cmcurl/lib/curl_threads.c4
-rw-r--r--Utilities/cmcurl/lib/dict.c2
-rw-r--r--Utilities/cmcurl/lib/easy.c5
-rw-r--r--Utilities/cmcurl/lib/easyoptions.c4
-rw-r--r--Utilities/cmcurl/lib/escape.c2
-rw-r--r--Utilities/cmcurl/lib/file.c25
-rw-r--r--Utilities/cmcurl/lib/formdata.c22
-rw-r--r--Utilities/cmcurl/lib/ftp.c250
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c6
-rw-r--r--Utilities/cmcurl/lib/getinfo.c8
-rw-r--r--Utilities/cmcurl/lib/gopher.c7
-rw-r--r--Utilities/cmcurl/lib/h2h3.c2
-rw-r--r--Utilities/cmcurl/lib/h2h3.h2
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c4
-rw-r--r--Utilities/cmcurl/lib/hostip.c4
-rw-r--r--Utilities/cmcurl/lib/hostip.h5
-rw-r--r--Utilities/cmcurl/lib/hostip4.c15
-rw-r--r--Utilities/cmcurl/lib/hostip6.c4
-rw-r--r--Utilities/cmcurl/lib/hostsyn.c4
-rw-r--r--Utilities/cmcurl/lib/hsts.c9
-rw-r--r--Utilities/cmcurl/lib/http.c254
-rw-r--r--Utilities/cmcurl/lib/http.h2
-rw-r--r--Utilities/cmcurl/lib/http2.c14
-rw-r--r--Utilities/cmcurl/lib/http2.h2
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c74
-rw-r--r--Utilities/cmcurl/lib/http_chunks.c2
-rw-r--r--Utilities/cmcurl/lib/http_digest.c2
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c2
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c1884
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h50
-rw-r--r--Utilities/cmcurl/lib/idn.c193
-rw-r--r--Utilities/cmcurl/lib/idn.h38
-rw-r--r--Utilities/cmcurl/lib/idn_win32.c121
-rw-r--r--Utilities/cmcurl/lib/imap.c30
-rw-r--r--Utilities/cmcurl/lib/krb5.c19
-rw-r--r--Utilities/cmcurl/lib/ldap.c8
-rw-r--r--Utilities/cmcurl/lib/md4.c73
-rw-r--r--Utilities/cmcurl/lib/md5.c65
-rw-r--r--Utilities/cmcurl/lib/mime.c34
-rw-r--r--Utilities/cmcurl/lib/mime.h16
-rw-r--r--Utilities/cmcurl/lib/mqtt.c4
-rw-r--r--Utilities/cmcurl/lib/multi.c241
-rw-r--r--Utilities/cmcurl/lib/multihandle.h8
-rw-r--r--Utilities/cmcurl/lib/nonblock.c3
-rw-r--r--Utilities/cmcurl/lib/noproxy.c24
-rw-r--r--Utilities/cmcurl/lib/openldap.c6
-rw-r--r--Utilities/cmcurl/lib/pingpong.c5
-rw-r--r--Utilities/cmcurl/lib/pop3.c32
-rw-r--r--Utilities/cmcurl/lib/rand.c4
-rw-r--r--Utilities/cmcurl/lib/rtsp.c32
-rw-r--r--Utilities/cmcurl/lib/rtsp.h2
-rw-r--r--Utilities/cmcurl/lib/sendf.c99
-rw-r--r--Utilities/cmcurl/lib/sendf.h5
-rw-r--r--Utilities/cmcurl/lib/setopt.c56
-rw-r--r--Utilities/cmcurl/lib/setup-os400.h8
-rw-r--r--Utilities/cmcurl/lib/sha256.c73
-rw-r--r--Utilities/cmcurl/lib/smb.c25
-rw-r--r--Utilities/cmcurl/lib/smtp.c53
-rw-r--r--Utilities/cmcurl/lib/socks.c457
-rw-r--r--Utilities/cmcurl/lib/socks.h30
-rw-r--r--Utilities/cmcurl/lib/strcase.c49
-rw-r--r--Utilities/cmcurl/lib/strcase.h8
-rw-r--r--Utilities/cmcurl/lib/strtoofft.c1
-rw-r--r--Utilities/cmcurl/lib/telnet.c16
-rw-r--r--Utilities/cmcurl/lib/transfer.c198
-rw-r--r--Utilities/cmcurl/lib/transfer.h1
-rw-r--r--Utilities/cmcurl/lib/url.c448
-rw-r--r--Utilities/cmcurl/lib/url.h22
-rw-r--r--Utilities/cmcurl/lib/urlapi.c2
-rw-r--r--Utilities/cmcurl/lib/urldata.h114
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c12
-rw-r--r--Utilities/cmcurl/lib/vauth/digest_sspi.c4
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_sspi.c2
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c2
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.h3
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.h4
-rw-r--r--Utilities/cmcurl/lib/version.c199
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.c160
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.h7
-rw-r--r--Utilities/cmcurl/lib/vquic/quiche.c5
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh.c18
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c28
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c6
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c186
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c223
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c662
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h41
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c238
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c13
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h2
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c332
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c1445
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c163
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c293
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h7
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c24
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c532
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c753
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h255
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls_int.h190
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c367
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.c62
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.h3
-rw-r--r--Utilities/cmcurl/lib/ws.c369
-rw-r--r--Utilities/cmcurl/lib/ws.h6
-rw-r--r--Utilities/cmnghttp2/CMakeLists.txt1
-rw-r--r--Utilities/cmnghttp2/cmakeconfig.h.in3
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h1150
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h4
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.c6
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.h2
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_extpri.c35
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_extpri.h65
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.c111
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.h49
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.c14
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.h1
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_helper.c176
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.c813
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.h51
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.c280
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.h70
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_net.h14
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.c22
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.h15
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.c3
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.h2
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.c3
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.h10
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.c840
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.h77
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.c21
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.h26
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_submit.c102
-rw-r--r--Utilities/std/cm/bits/string_view.cxx36
-rw-r--r--Utilities/std/cm/string_view4
-rw-r--r--Utilities/std/cmext/iterator8
1583 files changed, 30520 insertions, 14228 deletions
diff --git a/.clang-format b/.clang-format
index cba23d6..813a84d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,5 +1,5 @@
---
-# This configuration requires clang-format version 6.0 exactly.
+# This configuration requires clang-format version 15 exactly.
BasedOnStyle: Mozilla
AlignOperands: false
AllowShortFunctionsOnASingleLine: InlineOnly
diff --git a/.clang-tidy b/.clang-tidy
index a86f39a..c790467 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,24 +1,31 @@
---
Checks: "-*,\
bugprone-*,\
+-bugprone-assignment-in-if-condition,\
-bugprone-easily-swappable-parameters,\
-bugprone-implicit-widening-of-multiplication-result,\
-bugprone-macro-parentheses,\
-bugprone-misplaced-widening-cast,\
-bugprone-narrowing-conversions,\
-bugprone-too-small-loop-variable,\
+-bugprone-unchecked-optional-access,\
misc-*,\
+-misc-confusable-identifiers,\
+-misc-const-correctness,\
-misc-no-recursion,\
-misc-non-private-member-variables-in-classes,\
-misc-static-assert,\
modernize-*,\
-modernize-avoid-c-arrays,\
+-modernize-macro-to-enum,\
-modernize-return-braced-init-list,\
+-modernize-use-emplace,\
-modernize-use-nodiscard,\
-modernize-use-noexcept,\
-modernize-use-trailing-return-type,\
-modernize-use-transparent-functors,\
performance-*,\
+-performance-inefficient-vector-operation,\
readability-*,\
-readability-convert-member-functions-to-static,\
-readability-function-cognitive-complexity,\
@@ -28,11 +35,17 @@ readability-*,\
-readability-implicit-bool-conversion,\
-readability-inconsistent-declaration-parameter-name,\
-readability-magic-numbers,\
+-readability-make-member-function-const,\
-readability-named-parameter,\
-readability-redundant-declaration,\
-readability-redundant-member-init,\
+-readability-simplify-boolean-expr,\
-readability-suspicious-call-argument,\
-readability-uppercase-literal-suffix,\
+cmake-*,\
+-cmake-ostringstream-use-cmstrcat,\
+-cmake-string-concatenation-use-cmstrcat,\
+-cmake-use-bespoke-enum-class,\
"
HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$'
CheckOptions:
diff --git a/.gitattributes b/.gitattributes
index 71ecacf..96a1166 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,11 +4,11 @@
.editorconfig export-ignore
# Custom attribute to mark sources as using our C code style.
-[attr]our-c-style whitespace=tab-in-indent format.clang-format-6.0
+[attr]our-c-style whitespace=tab-in-indent format.clang-format=15
# 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
+[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format
bootstrap eol=lf
configure eol=lf
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6bd08ee..768a902 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,7 +16,6 @@ stages:
- build
- test
- test-ext
- - package
- upload
################################################################################
@@ -37,7 +36,6 @@ stages:
# Job prefixes:
# - `b:` build
-# - `k:` package
# - `l:` lint
# - `p:` prep
# - `t:` test
@@ -49,7 +47,7 @@ p:source-package:
extends:
- .linux_prep_source
- .cmake_prep_source_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .cmake_release_artifacts
- .run_only_for_package
variables:
@@ -57,9 +55,9 @@ p:source-package:
p:doc-package:
extends:
- - .fedora36_sphinx_package
+ - .fedora37_sphinx_package
- .cmake_prep_doc_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .cmake_doc_artifacts
- .run_only_for_package
@@ -95,38 +93,38 @@ u:cmake.org-help:
l:codespell:
extends:
- .cmake_codespell_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_automatically
l:iwyu-debian10:
extends:
- .debian10_iwyu
- .cmake_build_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_automatically
-l:tidy-fedora36:
+l:tidy-fedora37:
extends:
- - .fedora36_tidy
+ - .fedora37_tidy
- .cmake_build_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_automatically
-l:sphinx-fedora36:
+l:sphinx-fedora37:
extends:
- - .fedora36_sphinx
+ - .fedora37_sphinx
- .cmake_build_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_automatically
variables:
CMAKE_CI_JOB_CONTINUOUS: "true"
CMAKE_CI_JOB_HELP: "true"
-l:clang-analyzer-fedora36:
+l:clang-analyzer-fedora37:
extends:
- - .fedora36_clang_analyzer
+ - .fedora37_clang_analyzer
- .cmake_build_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_automatically
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
@@ -138,7 +136,7 @@ b:centos6-x86_64:
- .linux_release_x86_64
- .cmake_build_linux_release
- .cmake_release_artifacts
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_ARTIFACTS_NAME: "artifacts-centos6-x86_64"
@@ -148,7 +146,7 @@ b:centos7-aarch64:
- .linux_release_aarch64
- .cmake_build_linux_release
- .cmake_release_artifacts
- - .linux_builder_tags_aarch64
+ - .linux_aarch64_tags
- .run_manually
variables:
CMAKE_CI_ARTIFACTS_NAME: "artifacts-centos7-aarch64"
@@ -158,7 +156,7 @@ t:debian10-ninja:
extends:
- .debian10_ninja
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .cmake_junit_artifacts
- .run_dependent
- .needs_centos6_x86_64
@@ -169,7 +167,7 @@ t:debian10-aarch64-ninja:
extends:
- .debian10_aarch64_ninja
- .cmake_test_linux_release
- - .linux_builder_tags_aarch64
+ - .linux_aarch64_tags
- .cmake_junit_artifacts
- .run_dependent
- .needs_centos7_aarch64
@@ -180,8 +178,8 @@ t:debian10-ninja-clang:
extends:
- .debian10_ninja_clang
- .cmake_test_linux_release
- - .linux_builder_tags
- - .run_manually
+ - .linux_x86_64_tags
+ - .run_dependent
- .needs_centos6_x86_64
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
@@ -190,38 +188,68 @@ t:debian10-makefiles-clang:
extends:
- .debian10_makefiles_clang
- .cmake_test_linux_release
- - .linux_builder_tags
- - .run_manually
+ - .linux_x86_64_tags
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:fedora37-ninja-clang:
+ extends:
+ - .fedora37_ninja_clang
+ - .cmake_test_linux_release
+ - .linux_x86_64_tags
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:fedora37-makefiles-clang:
+ extends:
+ - .fedora37_makefiles_clang
+ - .cmake_test_linux_release
+ - .linux_x86_64_tags
+ - .run_dependent
- .needs_centos6_x86_64
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-t:fedora36-makefiles:
+t:fedora37-makefiles:
extends:
- - .fedora36_makefiles
+ - .fedora37_makefiles
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_dependent
- .needs_centos6_x86_64
-t:fedora36-makefiles-nospace:
+t:fedora37-makefiles-nospace:
extends:
- - .fedora36_makefiles
+ - .fedora37_makefiles
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .cmake_junit_artifacts
- .run_dependent
- .needs_centos6_x86_64
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake-ci"
- CMAKE_CI_BUILD_NAME: fedora36_makefiles_nospace
+ CMAKE_CI_BUILD_NAME: fedora37_makefiles_nospace
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:nvhpc22.11-ninja:
+ extends:
+ - .nvhpc_ninja
+ - .cmake_test_linux_release
+ - .linux_x86_64_v3_tags_cuda
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
CMAKE_CI_JOB_NIGHTLY: "true"
t:cuda9.2-nvidia:
extends:
- .cuda9.2_nvidia
- .cmake_test_linux_release
- - .linux_builder_tags_cuda
+ - .linux_x86_64_tags_cuda
- .run_dependent
- .needs_centos6_x86_64
variables:
@@ -231,7 +259,7 @@ t:cuda10.2-nvidia:
extends:
- .cuda10.2_nvidia
- .cmake_test_linux_release
- - .linux_builder_tags_cuda
+ - .linux_x86_64_tags_cuda
- .cmake_junit_artifacts
- .run_dependent
- .needs_centos6_x86_64
@@ -240,7 +268,7 @@ t:cuda10.2-clang:
extends:
- .cuda10.2_clang
- .cmake_test_linux_release
- - .linux_builder_tags_cuda
+ - .linux_x86_64_tags_cuda
- .run_dependent
- .needs_centos6_x86_64
variables:
@@ -250,7 +278,7 @@ t:cuda11.6-nvidia:
extends:
- .cuda11.6_nvidia
- .cmake_test_linux_release
- - .linux_builder_tags_cuda
+ - .linux_x86_64_tags_cuda
- .cmake_junit_artifacts
- .run_dependent
- .needs_centos6_x86_64
@@ -259,7 +287,17 @@ t:cuda11.6-clang:
extends:
- .cuda11.6_clang
- .cmake_test_linux_release
- - .linux_builder_tags_cuda
+ - .linux_x86_64_tags_cuda
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_NO_MR: "true"
+
+t:cuda11.8-minimal-ninja:
+ extends:
+ - .cuda11.8_minimal_nvidia
+ - .cmake_test_linux_release
+ - .linux_x86_64_tags_cuda
- .run_dependent
- .needs_centos6_x86_64
variables:
@@ -269,7 +307,7 @@ t:hip4.2-radeon:
extends:
- .hip4.2_radeon
- .cmake_test_linux_release
- - .linux_builder_tags_radeon
+ - .linux_x86_64_tags_radeon
- .run_dependent
- .needs_centos6_x86_64
variables:
@@ -279,7 +317,7 @@ t:linux-gcc-cxx-modules-ninja:
extends:
- .gcc_cxx_modules_ninja
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_dependent
- .needs_centos6_x86_64
variables:
@@ -289,18 +327,38 @@ t:linux-gcc-cxx-modules-ninja-multi:
extends:
- .gcc_cxx_modules_ninja_multi
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_dependent
- .needs_centos6_x86_64
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-b:fedora36-ninja:
+t:linux-clang-cxx-modules-ninja:
extends:
- - .fedora36_ninja
+ - .clang_cxx_modules_ninja
+ - .cmake_test_linux_release
+ - .linux_x86_64_tags
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:linux-clang-cxx-modules-ninja-multi:
+ extends:
+ - .clang_cxx_modules_ninja_multi
+ - .cmake_test_linux_release
+ - .linux_x86_64_tags
+ - .run_dependent
+ - .needs_centos6_x86_64
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+b:fedora37-ninja:
+ extends:
+ - .fedora37_ninja
- .cmake_build_linux
- .cmake_build_artifacts
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_JOB_CONTINUOUS: "true"
@@ -309,7 +367,7 @@ b:debian10-makefiles-inplace:
extends:
- .debian10_makefiles_inplace
- .cmake_build_linux_standalone
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
@@ -318,7 +376,7 @@ b:debian10-extdeps:
extends:
- .debian10_extdeps
- .cmake_build_linux_standalone
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
@@ -327,45 +385,45 @@ b:debian10-aarch64-extdeps:
extends:
- .debian10_aarch64_extdeps
- .cmake_build_linux_standalone
- - .linux_builder_tags_aarch64
+ - .linux_aarch64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-b:fedora36-extdeps:
+b:fedora37-extdeps:
extends:
- - .fedora36_extdeps
+ - .fedora37_extdeps
- .cmake_build_linux_standalone
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-t:fedora36-ninja:
+t:fedora37-ninja:
extends:
- - .fedora36_ninja
+ - .fedora37_ninja
- .cmake_test_linux
- - .linux_builder_tags_x11
+ - .linux_x86_64_tags_x11
- .cmake_test_artifacts
- .run_dependent
dependencies:
- - b:fedora36-ninja
+ - b:fedora37-ninja
needs:
- - b:fedora36-ninja
+ - b:fedora37-ninja
variables:
CMAKE_CI_JOB_CONTINUOUS: "true"
-t:fedora36-ninja-multi:
+t:fedora37-ninja-multi:
extends:
- - .fedora36_ninja_multi
+ - .fedora37_ninja_multi
- .cmake_test_linux_external
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .cmake_junit_artifacts
- .run_dependent
dependencies:
- - t:fedora36-ninja
+ - t:fedora37-ninja
needs:
- - t:fedora36-ninja
+ - t:fedora37-ninja
t:intel2016-makefiles:
extends:
@@ -598,6 +656,13 @@ t:intel2021.7.0-makefiles:
CMAKE_CI_BUILD_NAME: intel2021.7.0_makefiles
CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2022.2.0-el8
+t:intel2021.8.0-makefiles:
+ extends:
+ - .cmake_test_linux_intelclassic_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: intel2021.8.0_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2023.0.0-el8
+
t:oneapi2021.1.1-makefiles:
extends:
- .cmake_test_linux_inteloneapi_makefiles
@@ -654,13 +719,20 @@ t:oneapi2022.2.0-makefiles:
CMAKE_CI_BUILD_NAME: oneapi2022.2.0_makefiles
CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2022.2.0-el8
+t:oneapi2023.0.0-makefiles:
+ extends:
+ - .cmake_test_linux_inteloneapi_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: oneapi2023.0.0_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2023.0.0-el8
+
b:linux-x86_64-package:
extends:
- .linux_package
- .linux_release_x86_64
- .cmake_build_linux_release
- .cmake_release_artifacts
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_only_for_package
dependencies:
- p:doc-package
@@ -684,7 +756,7 @@ b:linux-aarch64-package:
- .linux_release_aarch64
- .cmake_build_linux_release
- .cmake_release_artifacts
- - .linux_builder_tags_aarch64
+ - .linux_aarch64_tags
- .run_only_for_package
dependencies:
- p:doc-package
@@ -704,26 +776,26 @@ u:linux-aarch64-package:
## Sanitizer builds
-b:fedora36-asan:
+b:fedora37-asan:
extends:
- - .fedora36_asan
+ - .fedora37_asan
- .cmake_build_linux
- .cmake_build_artifacts
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-t:fedora36-asan:
+t:fedora37-asan:
extends:
- - .fedora36_asan
+ - .fedora37_asan
- .cmake_memcheck_linux
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_dependent
dependencies:
- - b:fedora36-asan
+ - b:fedora37-asan
needs:
- - b:fedora36-asan
+ - b:fedora37-asan
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
@@ -734,15 +806,17 @@ b:macos-x86_64-ninja:
- .macos_x86_64_ninja
- .cmake_build_macos
- .cmake_build_artifacts
- - .macos_x86_64_builder_tags
+ - .macos_x86_64_tags
- .run_manually
+ variables:
+ CMAKE_CI_JOB_CONTINUOUS: "true"
b:macos-arm64-ninja:
extends:
- .macos_arm64_ninja
- .cmake_build_macos
- .cmake_build_artifacts
- - .macos_arm64_builder_tags
+ - .macos_arm64_tags
- .run_manually
variables:
CMAKE_CI_NO_MR: "true"
@@ -752,13 +826,14 @@ t:macos-x86_64-ninja:
- .macos_x86_64_ninja
- .cmake_test_macos
- .cmake_test_artifacts
- - .macos_x86_64_builder_tags
+ - .macos_x86_64_tags
- .run_dependent
dependencies:
- b:macos-x86_64-ninja
needs:
- b:macos-x86_64-ninja
variables:
+ CMAKE_CI_JOB_CONTINUOUS: "true"
CMAKE_CI_JOB_NIGHTLY_NINJA: "true"
t:macos-arm64-ninja:
@@ -766,7 +841,7 @@ t:macos-arm64-ninja:
- .macos_arm64_ninja
- .cmake_test_macos
- .cmake_test_artifacts
- - .macos_arm64_builder_tags
+ - .macos_arm64_tags
- .run_dependent
dependencies:
- b:macos-arm64-ninja
@@ -780,14 +855,14 @@ b:macos-x86_64-makefiles:
- .macos_x86_64_makefiles
- .cmake_build_macos
- .cmake_build_artifacts
- - .macos_x86_64_builder_tags
+ - .macos_x86_64_tags
- .run_manually
t:macos-x86_64-makefiles:
extends:
- .macos_x86_64_makefiles
- .cmake_test_macos
- - .macos_x86_64_builder_tags
+ - .macos_x86_64_tags
- .run_dependent
dependencies:
- b:macos-x86_64-makefiles
@@ -798,7 +873,7 @@ t:macos-x86_64-ninja-multi:
extends:
- .macos_x86_64_ninja_multi
- .cmake_test_macos_external
- - .macos_x86_64_builder_ext_tags
+ - .macos_x86_64_tags_ext
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -812,7 +887,7 @@ t:macos-x86_64-xcode:
extends:
- .macos_x86_64_xcode
- .cmake_test_macos_external
- - .macos_x86_64_builder_ext_tags
+ - .macos_x86_64_tags_ext
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -824,7 +899,7 @@ t:macos-arm64-xcode:
extends:
- .macos_arm64_xcode
- .cmake_test_macos_external
- - .macos_arm64_builder_ext_tags
+ - .macos_arm64_tags_ext
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -837,9 +912,9 @@ t:macos-arm64-xcode:
b:macos-package:
extends:
- .macos_package
- - .cmake_build_macos_package
+ - .cmake_build_macos
- .cmake_release_artifacts
- - .macos_x86_64_builder_tags_package
+ - .macos_x86_64_tags_package
- .run_only_for_package
dependencies:
- p:doc-package
@@ -860,9 +935,9 @@ u:macos-package:
b:macos10.10-package:
extends:
- .macos10.10_package
- - .cmake_build_macos_package
+ - .cmake_build_macos
- .cmake_release_artifacts
- - .macos_x86_64_builder_tags_package
+ - .macos_x86_64_tags_package
- .run_only_for_package
dependencies:
- p:doc-package
@@ -880,21 +955,21 @@ u:macos10.10-package:
needs:
- b:macos10.10-package
-# Windows builds
+# Windows x86_64 jobs
b:windows-vs2022-x64-ninja:
extends:
- .windows_vs2022_x64_ninja
- .cmake_build_windows
- .cmake_build_artifacts
- - .windows_tags_nonconcurrent_vs2022
+ - .windows_x86_64_tags_nonconcurrent_vs2022
- .run_manually
t:windows-vs2022-x64-ninja:
extends:
- .windows_vs2022_x64_ninja
- .cmake_test_windows
- - .windows_tags_nonconcurrent_vs2022
+ - .windows_x86_64_tags_nonconcurrent_vs2022
- .cmake_test_artifacts
- .run_dependent
dependencies:
@@ -908,7 +983,7 @@ t:windows-vs2022-x64-ninja-multi:
extends:
- .windows_vs2022_x64_ninja_multi
- .cmake_test_windows_external
- - .windows_tags_concurrent_vs2022
+ - .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -922,7 +997,7 @@ t:windows-vs2022-x64:
extends:
- .windows_vs2022_x64
- .cmake_test_windows_external
- - .windows_tags_concurrent_vs2022
+ - .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -934,7 +1009,7 @@ t:windows-vs2019-x64:
extends:
- .windows_vs2019_x64
- .cmake_test_windows_external
- - .windows_tags_concurrent_vs2019
+ - .windows_x86_64_tags_concurrent_vs2019
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -948,7 +1023,7 @@ t:windows-vs2022-x64-nmake:
extends:
- .windows_vs2022_x64_nmake
- .cmake_test_windows_nmake
- - .windows_tags_concurrent_vs2022
+ - .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -962,7 +1037,7 @@ t:windows-vs2022-x64-jom:
extends:
- .windows_vs2022_x64_jom
- .cmake_test_windows_jom
- - .windows_tags_concurrent_vs2022
+ - .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -976,7 +1051,7 @@ t:windows-borland5.5:
extends:
- .windows_borland5.5
- .cmake_test_windows_borland
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -990,7 +1065,7 @@ t:windows-borland5.8:
extends:
- .windows_borland5.8
- .cmake_test_windows_borland
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1004,7 +1079,7 @@ t:windows-clang15.0-cl-ninja:
extends:
- .windows_clang_ninja
- .cmake_test_windows_external
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1019,7 +1094,7 @@ t:windows-clang15.0-cl-nmake:
extends:
- .windows_clang_nmake
- .cmake_test_windows_external
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1034,7 +1109,7 @@ t:windows-clang15.0-gnu-ninja:
extends:
- .windows_clang_ninja
- .cmake_test_windows_external
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1049,7 +1124,7 @@ t:windows-clang15.0-gnu-nmake:
extends:
- .windows_clang_nmake
- .cmake_test_windows_external
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1060,11 +1135,39 @@ t:windows-clang15.0-gnu-nmake:
CMAKE_CI_BUILD_NAME: windows_clang15.0_gnu_nmake
CMAKE_CI_JOB_NIGHTLY: "true"
+t:mingw_osdn_io-mingw_makefiles:
+ extends:
+ - .mingw_osdn_io_mingw_makefiles
+ - .cmake_test_windows_external
+ - .windows_x86_64_tags_concurrent
+ - .cmake_junit_artifacts
+ - .run_dependent
+ dependencies:
+ - t:windows-vs2022-x64-ninja
+ needs:
+ - t:windows-vs2022-x64-ninja
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:mingw_osdn_io-msys_makefiles:
+ extends:
+ - .mingw_osdn_io_msys_makefiles
+ - .cmake_test_windows_external
+ - .windows_x86_64_tags_concurrent
+ - .cmake_junit_artifacts
+ - .run_dependent
+ dependencies:
+ - t:windows-vs2022-x64-ninja
+ needs:
+ - t:windows-vs2022-x64-ninja
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
t:windows-msvc-v71-nmake:
extends:
- .windows_msvc_v71_nmake
- .cmake_test_windows_msvc
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1078,7 +1181,7 @@ t:windows-openwatcom1.9:
extends:
- .windows_openwatcom1.9
- .cmake_test_windows_openwatcom
- - .windows_tags_concurrent
+ - .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
dependencies:
@@ -1088,31 +1191,59 @@ t:windows-openwatcom1.9:
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
-b:windows-x86_64-package:
+# Windows arm64 jobs
+
+b:windows-arm64-vs2022-ninja:
extends:
- - .windows_x86_64_package
+ - .windows_arm64_vs2022_ninja
- .cmake_build_windows
- - .cmake_build_package_artifacts
- - .windows_tags_nonconcurrent_vs2022
- - .run_only_for_package
+ - .cmake_build_artifacts
+ - .windows_arm64_tags_nonconcurrent_vs2022
+ - .run_manually
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:windows-arm64-vs2022-ninja:
+ extends:
+ - .windows_arm64_vs2022_ninja
+ - .cmake_test_windows
+ - .windows_arm64_tags_nonconcurrent_vs2022
+ - .cmake_test_artifacts
+ - .run_dependent
dependencies:
- - p:doc-package
+ - b:windows-arm64-vs2022-ninja
needs:
- - p:doc-package
+ - b:windows-arm64-vs2022-ninja
variables:
- CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-x86_64-build"
+ CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:windows-arm64-vs2022:
+ extends:
+ - .windows_arm64_vs2022
+ - .cmake_test_windows_external
+ - .windows_arm64_tags_concurrent_vs2022
+ - .cmake_junit_artifacts
+ - .run_dependent
+ dependencies:
+ - t:windows-arm64-vs2022-ninja
+ needs:
+ - t:windows-arm64-vs2022-ninja
+ variables:
+ CMAKE_CI_JOB_NIGHTLY: "true"
-k:windows-x86_64-package:
+# Windows package jobs
+
+b:windows-x86_64-package:
extends:
- .windows_x86_64_package
- - .cmake_package_windows
+ - .cmake_build_windows
- .cmake_release_artifacts
- - .windows_tags_nonconcurrent_vs2022
+ - .windows_x86_64_tags_nonconcurrent_vs2022
- .run_only_for_package
dependencies:
- - b:windows-x86_64-package
+ - p:doc-package
needs:
- - b:windows-x86_64-package
+ - p:doc-package
variables:
CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-x86_64"
@@ -1121,36 +1252,22 @@ u:windows-x86_64-package:
- .rsync_upload_package
- .run_only_for_package
dependencies:
- - k:windows-x86_64-package
+ - b:windows-x86_64-package
needs:
- - k:windows-x86_64-package
+ - b:windows-x86_64-package
b:windows-i386-package:
extends:
- .windows_i386_package
- .cmake_build_windows
- - .cmake_build_package_artifacts
- - .windows_tags_nonconcurrent_vs2022
+ - .cmake_release_artifacts
+ - .windows_x86_64_tags_nonconcurrent_vs2022
- .run_only_for_package
dependencies:
- p:doc-package
needs:
- p:doc-package
variables:
- CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-i386-build"
-
-k:windows-i386-package:
- extends:
- - .windows_i386_package
- - .cmake_package_windows
- - .cmake_release_artifacts
- - .windows_tags_nonconcurrent_vs2022
- - .run_only_for_package
- dependencies:
- - b:windows-i386-package
- needs:
- - b:windows-i386-package
- variables:
CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-i386"
u:windows-i386-package:
@@ -1158,36 +1275,22 @@ u:windows-i386-package:
- .rsync_upload_package
- .run_only_for_package
dependencies:
- - k:windows-i386-package
+ - b:windows-i386-package
needs:
- - k:windows-i386-package
+ - b:windows-i386-package
b:windows-arm64-package:
extends:
- .windows_arm64_package
- .cmake_build_windows
- - .cmake_build_package_artifacts
- - .windows_tags_nonconcurrent_vs2022_arm64
+ - .cmake_release_artifacts
+ - .windows_x86_64_tags_nonconcurrent_vs2022_arm64
- .run_only_for_package
dependencies:
- p:doc-package
needs:
- p:doc-package
variables:
- CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-arm64-build"
-
-k:windows-arm64-package:
- extends:
- - .windows_arm64_package
- - .cmake_package_windows
- - .cmake_release_artifacts
- - .windows_tags_nonconcurrent_vs2022_arm64
- - .run_only_for_package
- dependencies:
- - b:windows-arm64-package
- needs:
- - b:windows-arm64-package
- variables:
CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-arm64"
u:windows-arm64-package:
@@ -1195,6 +1298,6 @@ u:windows-arm64-package:
- .rsync_upload_package
- .run_only_for_package
dependencies:
- - k:windows-arm64-package
+ - b:windows-arm64-package
needs:
- - k:windows-arm64-package
+ - b:windows-arm64-package
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index d62e477..10d03ca 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -5,8 +5,10 @@
/ispc*
/jom
/llvm*
+/mingw
/msvc*
/ninja*
+/openmp
/open-watcom*
/python*
/qt*
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index 1b5384f..41f24ed 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -63,35 +63,6 @@
- build/DartConfiguation.tcl
- build/CTestCustom.cmake
-.cmake_build_package_artifacts:
- artifacts:
- expire_in: 1d
- name: "$CMAKE_CI_ARTIFACTS_NAME"
- paths:
- # Allow CPack to find CMAKE_ROOT.
- - build/CMakeFiles/CMakeSourceDir.txt
-
- # Install rules.
- - build/**/cmake_install.cmake
-
- # We need the main binaries.
- - build/bin/
-
- # Pass through the documentation.
- - build/install-doc/
-
- # CPack configuration.
- - build/CPackConfig.cmake
- - build/CMakeCPackOptions.cmake
- - build/Source/QtDialog/QtDialogCPack.cmake
-
- # CPack/IFW packaging files.
- - build/CMake*.qs
-
- # CPack/WIX packaging files.
- - build/Utilities/Release/WiX/custom_action_dll*.wxs
- - build/Utilities/Release/WiX/CustomAction/CMakeWiXCustomActions.*
-
.cmake_release_artifacts:
artifacts:
expire_in: 5d
@@ -109,6 +80,8 @@
# Any source packages made.
- build/cmake-*.tar.gz
- build/cmake-*.zip
+ # Any unsigned packages made.
+ - build/unsigned/cmake-*
.cmake_junit_artifacts:
artifacts:
diff --git a/.gitlab/ci/CMakeCPack.cmake b/.gitlab/ci/CMakeCPack.cmake
new file mode 100644
index 0000000..971fe54
--- /dev/null
+++ b/.gitlab/ci/CMakeCPack.cmake
@@ -0,0 +1,3 @@
+if(NOT "$ENV{CMAKE_CI_PACKAGE}" MATCHES "^(dev)?$")
+ configure_file(${CMAKE_CURRENT_LIST_DIR}/package_info.cmake.in ${CMake_BINARY_DIR}/ci_package_info.cmake @ONLY)
+endif()
diff --git a/.gitlab/ci/cmake.ps1 b/.gitlab/ci/cmake.ps1
index 98aeae3..3efb67a 100755
--- a/.gitlab/ci/cmake.ps1
+++ b/.gitlab/ci/cmake.ps1
@@ -1,8 +1,18 @@
$erroractionpreference = "stop"
$version = "3.24.1"
-$sha256sum = "C1B17431A16337D517F7BA78C7067B6F143A12686CB8087F3DD32F3FA45F5AAE"
-$filename = "cmake-$version-windows-x86_64"
+
+if ("$env:PROCESSOR_ARCHITECTURE" -eq "AMD64") {
+ $sha256sum = "C1B17431A16337D517F7BA78C7067B6F143A12686CB8087F3DD32F3FA45F5AAE"
+ $platform = "windows-x86_64"
+} elseif ("$env:PROCESSOR_ARCHITECTURE" -eq "ARM64") {
+ $sha256sum = "D94683F3B0E63F6EF194C621194F6E26F3735EDA70750395E0F2BBEE4023FB95"
+ $platform = "windows-arm64"
+} else {
+ throw ('unknown PROCESSOR_ARCHITECTURE: ' + "$env:PROCESSOR_ARCHITECTURE")
+}
+
+$filename = "cmake-$version-$platform"
$tarball = "$filename.zip"
$outdir = $pwd.Path
diff --git a/.gitlab/ci/codespell.sh b/.gitlab/ci/codespell.sh
new file mode 100755
index 0000000..fd052bd
--- /dev/null
+++ b/.gitlab/ci/codespell.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+result=0
+echo "Running codespell on source code..."
+codespell || result=1
+
+if [ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]; then
+ for COMMIT in $(git rev-list "^$CI_MERGE_REQUEST_DIFF_BASE_SHA" "$CI_COMMIT_SHA"); do
+ echo "Running codespell on commit message of $COMMIT..."
+ git show --format=%B -s "$COMMIT" | codespell - || result=1
+ done
+fi
+
+exit $result
diff --git a/.gitlab/ci/configure_cuda11.8_minimal_nvidia.cmake b/.gitlab/ci/configure_cuda11.8_minimal_nvidia.cmake
new file mode 100644
index 0000000..519699b
--- /dev/null
+++ b/.gitlab/ci/configure_cuda11.8_minimal_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
index 605f6ba..7407959 100644
--- a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
@@ -27,6 +27,7 @@ set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
set(CMake_TEST_FindICU "ON" CACHE BOOL "")
+set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "")
set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
set(CMake_TEST_FindJNI "ON" CACHE BOOL "")
set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
@@ -73,6 +74,7 @@ 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_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
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
index 1daa581..abe750d 100644
--- a/.gitlab/ci/configure_debian10_iwyu.cmake
+++ b/.gitlab/ci/configure_debian10_iwyu.cmake
@@ -1,4 +1,6 @@
set(CMake_RUN_IWYU ON CACHE BOOL "")
+# Uncomment to diagnose IWYU problems as needed.
+#set(CMake_IWYU_VERBOSE 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
index 214828a..e8d6d55 100644
--- a/.gitlab/ci/configure_debian10_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_ninja.cmake
@@ -31,6 +31,7 @@ set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
set(CMake_TEST_FindICU "ON" CACHE BOOL "")
+set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "")
set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
set(CMake_TEST_FindJNI "ON" CACHE BOOL "")
set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
@@ -79,6 +80,7 @@ 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_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
if (NOT "$ENV{SWIFTC}" STREQUAL "")
diff --git a/.gitlab/ci/configure_fedora36_clang_analyzer.cmake b/.gitlab/ci/configure_fedora36_clang_analyzer.cmake
deleted file mode 100644
index 456936b..0000000
--- a/.gitlab/ci/configure_fedora36_clang_analyzer.cmake
+++ /dev/null
@@ -1 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake")
diff --git a/.gitlab/ci/configure_fedora36_tidy.cmake b/.gitlab/ci/configure_fedora36_tidy.cmake
deleted file mode 100644
index 38414d3..0000000
--- a/.gitlab/ci/configure_fedora36_tidy.cmake
+++ /dev/null
@@ -1,3 +0,0 @@
-set(CMake_RUN_CLANG_TIDY ON CACHE BOOL "")
-
-include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake")
diff --git a/.gitlab/ci/configure_fedora36_asan.cmake b/.gitlab/ci/configure_fedora37_asan.cmake
index 51977d9..363e953 100644
--- a/.gitlab/ci/configure_fedora36_asan.cmake
+++ b/.gitlab/ci/configure_fedora37_asan.cmake
@@ -1,4 +1,4 @@
set(CMAKE_C_FLAGS "-fsanitize=address" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-fsanitize=address" CACHE STRING "")
-include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake")
diff --git a/.gitlab/ci/configure_fedora37_clang_analyzer.cmake b/.gitlab/ci/configure_fedora37_clang_analyzer.cmake
new file mode 100644
index 0000000..f4c4cdd
--- /dev/null
+++ b/.gitlab/ci/configure_fedora37_clang_analyzer.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake")
diff --git a/.gitlab/ci/configure_fedora36_common.cmake b/.gitlab/ci/configure_fedora37_common.cmake
index 4484e26..4484e26 100644
--- a/.gitlab/ci/configure_fedora36_common.cmake
+++ b/.gitlab/ci/configure_fedora37_common.cmake
diff --git a/.gitlab/ci/configure_fedora37_common_clang.cmake b/.gitlab/ci/configure_fedora37_common_clang.cmake
new file mode 100644
index 0000000..70c9df9
--- /dev/null
+++ b/.gitlab/ci/configure_fedora37_common_clang.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_Fortran_COMPILER "/usr/bin/flang-new" CACHE FILEPATH "")
+set(CMAKE_Fortran_COMPILER_ID "LLVMFlang" CACHE STRING "")
+set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 "1" CACHE BOOL "")
+set(CMAKE_Fortran_FLAGS "-flang-experimental-exec" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_fedora36_extdeps.cmake b/.gitlab/ci/configure_fedora37_extdeps.cmake
index 8e545f5..8e545f5 100644
--- a/.gitlab/ci/configure_fedora36_extdeps.cmake
+++ b/.gitlab/ci/configure_fedora37_extdeps.cmake
diff --git a/.gitlab/ci/configure_fedora36_makefiles.cmake b/.gitlab/ci/configure_fedora37_makefiles.cmake
index 11d1a08..725cc46 100644
--- a/.gitlab/ci/configure_fedora36_makefiles.cmake
+++ b/.gitlab/ci/configure_fedora37_makefiles.cmake
@@ -30,6 +30,7 @@ set(CMake_TEST_FindGTest "ON" CACHE BOOL "")
set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "")
set(CMake_TEST_FindIconv "ON" CACHE BOOL "")
set(CMake_TEST_FindICU "ON" CACHE BOOL "")
+set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "")
set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
set(CMake_TEST_FindJNI "ON" CACHE BOOL "")
set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
@@ -79,6 +80,7 @@ if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_ISPC "ON" CACHE STRING "")
endif()
set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
set(CMake_TEST_UseSWIG "ON" CACHE BOOL "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_fedora37_makefiles_clang.cmake b/.gitlab/ci/configure_fedora37_makefiles_clang.cmake
new file mode 100644
index 0000000..7b82a9a
--- /dev/null
+++ b/.gitlab/ci/configure_fedora37_makefiles_clang.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common_clang.cmake")
diff --git a/.gitlab/ci/configure_fedora36_ninja.cmake b/.gitlab/ci/configure_fedora37_ninja.cmake
index 45d9192..5b40677 100644
--- a/.gitlab/ci/configure_fedora36_ninja.cmake
+++ b/.gitlab/ci/configure_fedora37_ninja.cmake
@@ -2,6 +2,7 @@ set(CMake_TEST_GUI "ON" CACHE BOOL "")
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_ISPC "ON" CACHE STRING "")
endif()
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
# "Release" flags without "-DNDEBUG" so we get assertions.
set(CMAKE_C_FLAGS_RELEASE "-O3" CACHE STRING "")
@@ -10,4 +11,4 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE STRING "")
# Cover compilation with C++11 only and not higher standards.
set(CMAKE_CXX_STANDARD "11" CACHE STRING "")
-include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora36_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake")
diff --git a/.gitlab/ci/configure_fedora37_ninja_clang.cmake b/.gitlab/ci/configure_fedora37_ninja_clang.cmake
new file mode 100644
index 0000000..7b82a9a
--- /dev/null
+++ b/.gitlab/ci/configure_fedora37_ninja_clang.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common_clang.cmake")
diff --git a/.gitlab/ci/configure_fedora36_ninja_multi.cmake b/.gitlab/ci/configure_fedora37_ninja_multi.cmake
index 94af721..94af721 100644
--- a/.gitlab/ci/configure_fedora36_ninja_multi.cmake
+++ b/.gitlab/ci/configure_fedora37_ninja_multi.cmake
diff --git a/.gitlab/ci/configure_fedora36_sphinx.cmake b/.gitlab/ci/configure_fedora37_sphinx.cmake
index 90d159b..90d159b 100644
--- a/.gitlab/ci/configure_fedora36_sphinx.cmake
+++ b/.gitlab/ci/configure_fedora37_sphinx.cmake
diff --git a/.gitlab/ci/configure_fedora36_sphinx_package.cmake b/.gitlab/ci/configure_fedora37_sphinx_package.cmake
index e839de8..e839de8 100644
--- a/.gitlab/ci/configure_fedora36_sphinx_package.cmake
+++ b/.gitlab/ci/configure_fedora37_sphinx_package.cmake
diff --git a/.gitlab/ci/configure_fedora37_tidy.cmake b/.gitlab/ci/configure_fedora37_tidy.cmake
new file mode 100644
index 0000000..f8eb9ab
--- /dev/null
+++ b/.gitlab/ci/configure_fedora37_tidy.cmake
@@ -0,0 +1,5 @@
+set(CMake_RUN_CLANG_TIDY ON CACHE BOOL "")
+set(CMake_USE_CLANG_TIDY_MODULE ON CACHE BOOL "")
+set(CMake_CLANG_TIDY_MODULE "$ENV{CI_PROJECT_DIR}/Utilities/ClangTidyModule/build/libcmake-clang-tidy-module.so" CACHE FILEPATH "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora37_common.cmake")
diff --git a/.gitlab/ci/configure_linux_clang_cxx_modules_ninja.cmake b/.gitlab/ci/configure_linux_clang_cxx_modules_ninja.cmake
new file mode 100644
index 0000000..43bccdb
--- /dev/null
+++ b/.gitlab/ci/configure_linux_clang_cxx_modules_ninja.cmake
@@ -0,0 +1,4 @@
+set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_linux_clang_cxx_modules_ninja_multi.cmake b/.gitlab/ci/configure_linux_clang_cxx_modules_ninja_multi.cmake
new file mode 100644
index 0000000..43bccdb
--- /dev/null
+++ b/.gitlab/ci/configure_linux_clang_cxx_modules_ninja_multi.cmake
@@ -0,0 +1,4 @@
+set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake
index 2b04e89..110df76 100644
--- a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake
+++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake
@@ -1,4 +1,4 @@
-set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,collation,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake
index 2b04e89..110df76 100644
--- a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake
+++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake
@@ -1,4 +1,4 @@
-set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,collation,partitions,internal_partitions,export_bmi,install_bmi" CACHE STRING "")
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_ninja.cmake b/.gitlab/ci/configure_macos_arm64_ninja.cmake
index f657d98..f59b43c 100644
--- a/.gitlab/ci/configure_macos_arm64_ninja.cmake
+++ b/.gitlab/ci/configure_macos_arm64_ninja.cmake
@@ -1,3 +1,7 @@
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
set(CMake_TEST_GUI "ON" CACHE BOOL "")
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
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
index d3ef93f..3c5d8fe 100644
--- a/.gitlab/ci/configure_macos_x86_64_makefiles.cmake
+++ b/.gitlab/ci/configure_macos_x86_64_makefiles.cmake
@@ -1,7 +1,11 @@
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
set(CMake_TEST_GUI "ON" CACHE BOOL "")
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_ISPC "ON" CACHE STRING "")
endif()
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
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
index d3ef93f..3c5d8fe 100644
--- a/.gitlab/ci/configure_macos_x86_64_ninja.cmake
+++ b/.gitlab/ci/configure_macos_x86_64_ninja.cmake
@@ -1,7 +1,11 @@
+set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
set(CMake_TEST_GUI "ON" CACHE BOOL "")
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_ISPC "ON" CACHE STRING "")
endif()
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_common.cmake b/.gitlab/ci/configure_mingw_osdn_io_common.cmake
new file mode 100644
index 0000000..55dce1d
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_common.cmake
@@ -0,0 +1,5 @@
+set(CMake_TEST_Java OFF CACHE BOOL "")
+
+set(configure_no_sccache 1)
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake b/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake
new file mode 100644
index 0000000..5ddd410
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_mingw_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_mingw_osdn_io_common.cmake")
diff --git a/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake b/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake
new file mode 100644
index 0000000..5ddd410
--- /dev/null
+++ b/.gitlab/ci/configure_mingw_osdn_io_msys_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_mingw_osdn_io_common.cmake")
diff --git a/.gitlab/ci/configure_nvhpc_ninja.cmake b/.gitlab/ci/configure_nvhpc_ninja.cmake
new file mode 100644
index 0000000..ca8ba93
--- /dev/null
+++ b/.gitlab/ci/configure_nvhpc_ninja.cmake
@@ -0,0 +1,5 @@
+set(CMake_TEST_CUDA "NVIDIA" CACHE STRING "")
+
+set(configure_no_sccache 1)
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_windows_arm64_vs2022.cmake b/.gitlab/ci/configure_windows_arm64_vs2022.cmake
new file mode 100644
index 0000000..c7d41ea
--- /dev/null
+++ b/.gitlab/ci/configure_windows_arm64_vs2022.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common.cmake")
diff --git a/.gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake b/.gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake
new file mode 100644
index 0000000..a12ee6c
--- /dev/null
+++ b/.gitlab/ci/configure_windows_arm64_vs2022_ninja.cmake
@@ -0,0 +1,8 @@
+# Qt host tools are not yet available natively on windows-arm64.
+set(CMake_TEST_GUI "OFF" CACHE BOOL "")
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
+set(BUILD_QtDialog "OFF" CACHE BOOL "")
+set(CMAKE_PREFIX_PATH "" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_msvc_cxx_modules_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common_ninja.cmake")
diff --git a/.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake b/.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake
index 8570196..38dd729 100644
--- a/.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake
+++ b/.gitlab/ci/configure_windows_msvc_cxx_modules_common.cmake
@@ -1,2 +1,2 @@
-set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,shared,export_bmi,install_bmi" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,collation,partitions,internal_partitions,shared,export_bmi,install_bmi" CACHE STRING "")
set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_msvc.cmake" CACHE STRING "")
diff --git a/.gitlab/ci/configure_windows_package_common.cmake b/.gitlab/ci/configure_windows_package_common.cmake
index 46c0a3e..b3929a4 100644
--- a/.gitlab/ci/configure_windows_package_common.cmake
+++ b/.gitlab/ci/configure_windows_package_common.cmake
@@ -19,4 +19,6 @@ set(CMake_TEST_Qt5 OFF CACHE BOOL "")
set(CMake_TEST_Qt6 OFF CACHE BOOL "")
set(Python_FIND_REGISTRY NEVER CACHE STRING "")
+set(CMake_CPACK_CUSTOM_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/CMakeCPack.cmake" CACHE FILEPATH "")
+
include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2022_x64.cmake b/.gitlab/ci/configure_windows_vs2022_x64.cmake
index c7d41ea..1e0f584 100644
--- a/.gitlab/ci/configure_windows_vs2022_x64.cmake
+++ b/.gitlab/ci/configure_windows_vs2022_x64.cmake
@@ -1 +1,4 @@
+set(CMake_TEST_MODULE_COMPILATION "named,partitions" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_msvc_cxx_modules_common.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
index f5a6d80..5bf0be8 100644
--- a/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
+++ b/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
@@ -1,6 +1,7 @@
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
set(CMake_TEST_ISPC "ON" CACHE STRING "")
endif()
+set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_msvc_cxx_modules_common.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common_ninja.cmake")
diff --git a/.gitlab/ci/ctest_build.cmake b/.gitlab/ci/ctest_build.cmake
index 4bb2924..e874a62 100644
--- a/.gitlab/ci/ctest_build.cmake
+++ b/.gitlab/ci/ctest_build.cmake
@@ -22,9 +22,32 @@ elseif (CTEST_CMAKE_GENERATOR MATCHES "Ninja")
set(CTEST_BUILD_FLAGS "-l${nproc}")
endif ()
+set(ctest_build_args)
+
+# IWYU debugging:
+# - set the name of the target (if not one of the main libraries)
+# - set the name of the source (without extension, relative to `Source/`)
+# - uncomment the debugging support in the relevant `configure_*_iwyu.cmake` file
+set(iwyu_source_target) # set for "other" targets not the "main" 3 libraries
+set(iwyu_source_name) # e.g., cmTarget
+if (iwyu_source_name AND "$ENV{CMAKE_CONFIGURATION}" MATCHES "iwyu")
+ if (NOT iwyu_source_target)
+ if (iwyu_source_name MATCHES "^(CTest/|cmCTest$)")
+ set(iwyu_source_target "CTestLib")
+ elseif (iwyu_source_name MATCHES "^CPack/")
+ set(iwyu_source_target "CPackLib")
+ else () # Assume everything else is in CMakeLib
+ set(iwyu_source_target "CMakeLib")
+ endif ()
+ endif ()
+ list(APPEND ctest_build_args
+ TARGET "Source/CMakeFiles/${iwyu_source_target}.dir/${iwyu_source_name}.cxx.o")
+endif ()
+
ctest_build(
NUMBER_WARNINGS num_warnings
- RETURN_VALUE build_result)
+ RETURN_VALUE build_result
+ ${ctest_build_args})
ctest_submit(PARTS Build)
if (build_result)
@@ -37,6 +60,11 @@ if ("$ENV{CTEST_NO_WARNINGS_ALLOWED}" AND num_warnings GREATER 0)
"Found ${num_warnings} warnings (treating as fatal).")
endif ()
+if (ctest_build_args)
+ message(FATAL_ERROR
+ "Failing to prevent debugging support from being committed.")
+endif ()
+
if (NOT "$ENV{CMAKE_CI_NO_INSTALL}")
ctest_build(APPEND
TARGET install
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index 89a5ace..a2789c3 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -27,6 +27,13 @@ if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "_jom")
)
endif()
+if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "nvhpc_")
+ list(APPEND test_exclusions
+ # FIXME(#24187): This test fails with NVHPC as the CUDA host compiler.
+ "^CudaOnly.SeparateCompilationPTX$"
+ )
+endif()
+
string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
if (test_exclusions)
set(test_exclusions "(${test_exclusions})")
diff --git a/.gitlab/ci/ctest_memcheck_fedora36_asan.lsan.supp b/.gitlab/ci/ctest_memcheck_fedora37_asan.lsan.supp
index 8ec1a03..8ec1a03 100644
--- a/.gitlab/ci/ctest_memcheck_fedora36_asan.lsan.supp
+++ b/.gitlab/ci/ctest_memcheck_fedora37_asan.lsan.supp
diff --git a/.gitlab/ci/cxx_modules_rules_clang.cmake b/.gitlab/ci/cxx_modules_rules_clang.cmake
new file mode 100644
index 0000000..fcb2281
--- /dev/null
+++ b/.gitlab/ci/cxx_modules_rules_clang.cmake
@@ -0,0 +1,18 @@
+set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3")
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
+ "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}"
+ " -format=p1689"
+ " --"
+ " <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>"
+ " -x c++ <SOURCE> -c -o <OBJECT>"
+ " -MT <DYNDEP_FILE>"
+ " -MD -MF <DEP_FILE>"
+ " > <DYNDEP_FILE>")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
+
+# Default to C++ extensions being off. Clang's modules support have trouble
+# with extensions right now.
+set(CMAKE_CXX_EXTENSIONS OFF)
diff --git a/.gitlab/ci/docker/clang_cxx_modules/Dockerfile b/.gitlab/ci/docker/clang_cxx_modules/Dockerfile
new file mode 100644
index 0000000..4e58125
--- /dev/null
+++ b/.gitlab/ci/docker/clang_cxx_modules/Dockerfile
@@ -0,0 +1,13 @@
+FROM fedora:37
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+# Install build dependencies for packages.
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
+
+COPY install_llvm.sh /root/install_llvm.sh
+RUN sh /root/install_llvm.sh
+
+# Install build dependencies for CMake's CI.
+COPY install_cmake_deps.sh /root/install_cmake_deps.sh
+RUN sh /root/install_cmake_deps.sh
diff --git a/.gitlab/ci/docker/clang_cxx_modules/install_cmake_deps.sh b/.gitlab/ci/docker/clang_cxx_modules/install_cmake_deps.sh
new file mode 100755
index 0000000..465e125
--- /dev/null
+++ b/.gitlab/ci/docker/clang_cxx_modules/install_cmake_deps.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+
+dnf install -y --setopt=install_weak_deps=False \
+ file git-core
+dnf clean all
diff --git a/.gitlab/ci/docker/clang_cxx_modules/install_deps.sh b/.gitlab/ci/docker/clang_cxx_modules/install_deps.sh
new file mode 100755
index 0000000..c1957c3
--- /dev/null
+++ b/.gitlab/ci/docker/clang_cxx_modules/install_deps.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+
+dnf install -y --setopt=install_weak_deps=False \
+ gcc-c++ cmake ninja-build
+dnf clean all
diff --git a/.gitlab/ci/docker/clang_cxx_modules/install_llvm.sh b/.gitlab/ci/docker/clang_cxx_modules/install_llvm.sh
new file mode 100755
index 0000000..35f925e
--- /dev/null
+++ b/.gitlab/ci/docker/clang_cxx_modules/install_llvm.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+set -e
+
+readonly revision="6d859df46e93e04bd7a4f90d9a9056763998f638" # llvmorg-16.0.0-rc2-31-g6d859df46e93
+readonly tarball="https://github.com/llvm/llvm-project/archive/$revision.tar.gz"
+
+readonly workdir="$HOME/llvm"
+readonly srcdir="$workdir/llvm"
+readonly builddir="$workdir/build"
+
+mkdir -p "$workdir"
+cd "$workdir"
+curl -L "$tarball" > "llvm-$revision.tar.gz"
+tar xf "llvm-$revision.tar.gz"
+mv "llvm-project-$revision" "$srcdir"
+mkdir -p "$builddir"
+cd "$builddir"
+cmake -GNinja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DBUILD_SHARED_LIBS=ON \
+ -DLLVM_ENABLE_BINDINGS=OFF \
+ -DLLVM_INCLUDE_BENCHMARKS=OFF \
+ -DLLVM_INCLUDE_DOCS=OFF \
+ -DLLVM_INCLUDE_EXAMPLES=OFF \
+ -DLLVM_INCLUDE_RUNTIMES=OFF \
+ -DLLVM_INCLUDE_TESTS=OFF \
+ -DLLVM_INCLUDE_UTILS=OFF \
+ -DLLVM_TARGETS_TO_BUILD=X86 \
+ -DLLVM_TOOL_CLANG_BUILD=ON \
+ -DLLVM_USE_SYMLINKS=ON \
+ "-DLLVM_EXTERNAL_CLANG_SOURCE_DIR=$srcdir/clang" \
+ -DLLVM_PARALLEL_LINK_JOBS=1 \
+ -DCLANG_BUILD_TOOLS=ON \
+ "-DCMAKE_INSTALL_PREFIX=/opt/llvm-p1689" \
+ "$srcdir/llvm"
+ninja
+ninja install/strip
+rm -rf "$workdir"
diff --git a/.gitlab/ci/docker/cuda10.2/Dockerfile b/.gitlab/ci/docker/cuda10.2/Dockerfile
index b6f37b5..cd30446 100644
--- a/.gitlab/ci/docker/cuda10.2/Dockerfile
+++ b/.gitlab/ci/docker/cuda10.2/Dockerfile
@@ -1,4 +1,4 @@
-FROM nvidia/cuda:10.2-devel-ubuntu18.04
+FROM kitware/nvidia-cuda:10.2-devel-ubuntu18.04
MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
COPY llvm.list /etc/apt/sources.list.d/llvm.list
diff --git a/.gitlab/ci/docker/cuda11.6/Dockerfile b/.gitlab/ci/docker/cuda11.6/Dockerfile
index 27cdf8b..f69b0fd 100644
--- a/.gitlab/ci/docker/cuda11.6/Dockerfile
+++ b/.gitlab/ci/docker/cuda11.6/Dockerfile
@@ -1,4 +1,4 @@
-FROM nvidia/cuda:11.6.0-devel-ubuntu20.04
+FROM kitware/nvidia-cuda:11.6.0-devel-ubuntu20.04
MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
COPY llvm.list /etc/apt/sources.list.d/llvm.list
diff --git a/.gitlab/ci/docker/cuda11.8-minimal/Dockerfile b/.gitlab/ci/docker/cuda11.8-minimal/Dockerfile
new file mode 100644
index 0000000..e185848
--- /dev/null
+++ b/.gitlab/ci/docker/cuda11.8-minimal/Dockerfile
@@ -0,0 +1,5 @@
+FROM kitware/nvidia-cuda:11.8.0-devel-ubuntu20.04
+MAINTAINER Robert Maynard <rmaynard@nvidia.com>
+
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/cuda11.8-minimal/install_deps.sh b/.gitlab/ci/docker/cuda11.8-minimal/install_deps.sh
new file mode 100755
index 0000000..55f4ce5
--- /dev/null
+++ b/.gitlab/ci/docker/cuda11.8-minimal/install_deps.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install dependency without interaction.
+env DEBIAN_FRONTEND=noninteractive \
+ TZ=America/New_York \
+ apt-get install -y \
+ tzdata
+
+# Install development tools.
+apt-get install -y \
+ g++ \
+ curl \
+ git
+
+# Reduce to minimal subset of libraries by removing static libraries
+mkdir /tmp/cuda_required
+mv /usr/local/cuda/lib64/libcuda* /tmp/cuda_required/
+rm -f /usr/local/cuda/lib64/*static.a
+mv /tmp/cuda_required/libcuda* /usr/local/cuda/lib64/
+rmdir /tmp/cuda_required
+
+apt-get clean
diff --git a/.gitlab/ci/docker/cuda9.2/Dockerfile b/.gitlab/ci/docker/cuda9.2/Dockerfile
index 7eae886..d7e483b 100644
--- a/.gitlab/ci/docker/cuda9.2/Dockerfile
+++ b/.gitlab/ci/docker/cuda9.2/Dockerfile
@@ -1,4 +1,4 @@
-FROM nvidia/cuda:9.2-devel-ubuntu16.04
+FROM kitware/nvidia-cuda:9.2-devel-ubuntu16.04
MAINTAINER Brad King <brad.king@kitware.com>
COPY install_deps.sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/debian10-aarch64/Dockerfile b/.gitlab/ci/docker/debian10-aarch64/Dockerfile
index 2079795..a0687e3 100644
--- a/.gitlab/ci/docker/debian10-aarch64/Dockerfile
+++ b/.gitlab/ci/docker/debian10-aarch64/Dockerfile
@@ -1,5 +1,26 @@
-FROM arm64v8/debian:10
-MAINTAINER Brad King <brad.king@kitware.com>
+# syntax=docker/dockerfile:1
-COPY install_deps.sh /root/install_deps.sh
-RUN sh /root/install_deps.sh
+ARG BASE_IMAGE=arm64v8/debian:10
+
+FROM ${BASE_IMAGE} AS apt-cache
+# Populate APT cache w/ the fresh metadata and prefetch packages.
+# Use an empty `docker-clean` file to "hide" the image-provided
+# file to disallow removing packages after `apt-get` operations.
+RUN --mount=type=tmpfs,target=/var/log \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ apt-get update \
+ && apt-get --download-only -y install $(grep -h '^[^#]\+$' /root/*.lst)
+
+FROM ${BASE_IMAGE}
+LABEL maintainer="Brad King <brad.king@kitware.com>"
+
+RUN --mount=type=bind,source=install_deps.sh,target=/root/install_deps.sh \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=bind,source=dpkg-exclude,target=/etc/dpkg/dpkg.cfg.d/exclude \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+ --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst b/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst
new file mode 100644
index 0000000..5e30e16
--- /dev/null
+++ b/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst
@@ -0,0 +1,90 @@
+# Install build requirements.
+libssl-dev
+
+# Install development tools.
+g++
+curl
+git
+
+# Install optional external build dependencies.
+libarchive-dev
+libbz2-dev
+libcurl4-gnutls-dev
+libexpat1-dev
+libjsoncpp-dev
+liblzma-dev
+libncurses-dev
+librhash-dev
+libuv1-dev
+libzstd-dev
+zlib1g-dev
+
+# Install iwyu runtime deps.
+clang-6.0
+libncurses6
+
+# Tools needed for the test suite.
+jq
+
+# Packages needed to test CTest.
+bzr bzr-xmloutput
+cvs
+subversion
+mercurial
+
+# Packages needed to test find modules.
+alsa-utils
+doxygen graphviz
+freeglut3-dev
+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
+libgmock-dev
+libgrpc++-dev libgrpc-dev
+libgsl-dev
+libgtest-dev
+libgtk2.0-dev
+libicu-dev
+libinput-dev
+libjpeg-dev
+libjsoncpp-dev
+liblapack-dev
+liblzma-dev
+libmagick++-dev
+libopenal-dev
+libopenmpi-dev openmpi-bin
+libosp-dev
+libpng-dev
+libpq-dev postgresql-server-dev-11
+libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler protobuf-compiler-grpc
+libsdl-dev
+libsqlite3-dev
+libtiff-dev
+libuv1-dev
+libx11-dev
+libxalan-c-dev
+libxerces-c-dev
+libxml2-dev libxml2-utils
+libxslt-dev xsltproc
+openjdk-11-jdk
+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
diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt b/.gitlab/ci/docker/debian10-aarch64/docker-clean
index e69de29..e69de29 100644
--- a/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt
+++ b/.gitlab/ci/docker/debian10-aarch64/docker-clean
diff --git a/.gitlab/ci/docker/debian10-aarch64/dpkg-exclude b/.gitlab/ci/docker/debian10-aarch64/dpkg-exclude
new file mode 100644
index 0000000..60b6565
--- /dev/null
+++ b/.gitlab/ci/docker/debian10-aarch64/dpkg-exclude
@@ -0,0 +1,21 @@
+# Drop all man pages
+path-exclude=/usr/share/man/*
+
+# Drop all info pages
+path-exclude=/usr/share/info/*
+
+# Drop all README files except from the some packages
+path-exclude=/usr/**/*README*
+path-include=/usr/share/devscripts/templates/README.mk-build-deps
+path-include=/usr/share/equivs/template/debian/README.Debian.in
+
+# Drop all translations
+path-exclude=/usr/share/locale/*/LC_MESSAGES/*.mo
+
+# Drop all documentation ...
+path-exclude=/usr/share/doc/*
+path-exclude=/usr/share/doc-base/*
+path-exclude=/usr/share/gtk-doc/*
+
+# Per package excludes
+path-exclude=/usr/share/gnupg/help.*.txt
diff --git a/.gitlab/ci/docker/debian10-aarch64/install_deps.sh b/.gitlab/ci/docker/debian10-aarch64/install_deps.sh
index 8b5a001..d1c8aed 100755
--- a/.gitlab/ci/docker/debian10-aarch64/install_deps.sh
+++ b/.gitlab/ci/docker/debian10-aarch64/install_deps.sh
@@ -2,103 +2,4 @@
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 optional external build dependencies.
-apt-get install -y \
- libarchive-dev \
- libbz2-dev \
- libcurl4-gnutls-dev \
- libexpat1-dev \
- libjsoncpp-dev \
- liblzma-dev \
- libncurses-dev \
- librhash-dev \
- libuv1-dev \
- libzstd-dev \
- zlib1g-dev
-
-# 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 CTest.
-apt-get install -y \
- bzr bzr-xmloutput \
- cvs \
- subversion \
- mercurial
-
-# Packages needed to test find modules.
-apt-get install -y \
- alsa-utils \
- doxygen graphviz \
- freeglut3-dev \
- 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 \
- libgmock-dev \
- libgrpc++-dev libgrpc-dev \
- libgsl-dev \
- libgtest-dev \
- libgtk2.0-dev \
- libicu-dev \
- libinput-dev \
- libjpeg-dev \
- libjsoncpp-dev \
- liblapack-dev \
- liblzma-dev \
- libopenal-dev \
- libopenmpi-dev openmpi-bin \
- libosp-dev \
- libpng-dev \
- libpq-dev postgresql-server-dev-11 \
- libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler protobuf-compiler-grpc \
- libsdl-dev \
- libsqlite3-dev \
- libtiff-dev \
- libuv1-dev \
- libx11-dev \
- libxalan-c-dev \
- libxerces-c-dev \
- libxml2-dev libxml2-utils \
- libxslt-dev xsltproc \
- openjdk-11-jdk \
- 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
+apt-get install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
diff --git a/.gitlab/ci/docker/debian10/Dockerfile b/.gitlab/ci/docker/debian10/Dockerfile
index 34a4bf1..d866428 100644
--- a/.gitlab/ci/docker/debian10/Dockerfile
+++ b/.gitlab/ci/docker/debian10/Dockerfile
@@ -1,25 +1,62 @@
-FROM debian:10 as iwyu-build
-MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+# syntax=docker/dockerfile:1
-COPY install_iwyu.sh /root/install_iwyu.sh
-RUN sh /root/install_iwyu.sh
+ARG BASE_IMAGE=debian:10
-FROM debian:10 as rvm-build
-MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+FROM ${BASE_IMAGE} AS apt-cache
+# Populate APT cache w/ the fresh metadata and prefetch packages.
+# Use an empty `docker-clean` file to "hide" the image-provided
+# file to disallow removing packages after `apt-get` operations.
+RUN --mount=type=tmpfs,target=/var/log \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=bind,source=iwyu_packages.lst,target=/root/iwyu_packages.lst \
+ --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
+ apt-get update \
+ && apt-get --download-only -y install $(grep -h '^[^#]\+$' /root/*.lst)
-COPY install_rvm.sh /root/install_rvm.sh
-RUN sh /root/install_rvm.sh
-FROM debian:10
-MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+FROM ${BASE_IMAGE} AS iwyu-build
+LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
-COPY install_deps.sh /root/install_deps.sh
-RUN sh /root/install_deps.sh
+RUN --mount=type=bind,source=install_iwyu.sh,target=/root/install_iwyu.sh \
+ --mount=type=bind,source=iwyu_packages.lst,target=/root/iwyu_packages.lst \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+ --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_iwyu.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
+FROM ${BASE_IMAGE} AS rvm-build
+LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+
+RUN --mount=type=bind,source=install_rvm.sh,target=/root/install_rvm.sh \
+ --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+ --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_rvm.sh
+
+
+FROM ${BASE_IMAGE}
+LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+
+RUN --mount=type=bind,source=install_deps.sh,target=/root/install_deps.sh \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=bind,source=dpkg-exclude,target=/etc/dpkg/dpkg.cfg.d/exclude \
+ --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+ --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+ --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_deps.sh
+
+RUN --mount=type=bind,from=iwyu-build,source=/root,target=/root \
+ tar -C / -xf /root/iwyu.tar \
+ && ln -s /usr/lib/llvm-6.0/bin/include-what-you-use /usr/bin/include-what-you-use-6.0
+
+RUN --mount=type=bind,from=rvm-build,source=/root,target=/root \
+ tar -C /usr/local -xf /root/rvm.tar
diff --git a/.gitlab/ci/docker/debian10/deps_packages.lst b/.gitlab/ci/docker/debian10/deps_packages.lst
new file mode 100644
index 0000000..3df41f5
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/deps_packages.lst
@@ -0,0 +1,96 @@
+# Install build requirements.
+libssl-dev
+
+# Install development tools.
+g++
+curl
+git
+
+# Install optional external build dependencies.
+libarchive-dev
+libbz2-dev
+libcurl4-gnutls-dev
+libexpat1-dev
+libjsoncpp-dev
+liblzma-dev
+libncurses-dev
+librhash-dev
+libuv1-dev
+libzstd-dev
+zlib1g-dev
+
+# Install iwyu runtime deps.
+clang-6.0
+libncurses6
+
+# Tools needed for the test suite.
+jq
+
+# Packages needed to test CTest.
+bzr bzr-xmloutput
+cvs
+subversion
+mercurial
+
+# Install swift runtime deps.
+libncurses5
+
+# Packages needed to test find modules.
+alsa-utils
+doxygen graphviz
+freeglut3-dev
+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
+libgmock-dev
+libgrpc++-dev libgrpc-dev
+libgsl-dev
+libgtest-dev
+libgtk2.0-dev
+libicu-dev
+libinput-dev
+libjpeg-dev
+libjsoncpp-dev
+liblapack-dev
+liblzma-dev
+libmagick++-dev
+libopenal-dev
+libopenmpi-dev openmpi-bin
+libosp-dev
+libpng-dev
+libpq-dev postgresql-server-dev-11
+libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler protobuf-compiler-grpc
+libsdl-dev
+libsqlite3-dev
+libtiff-dev
+libuv1-dev
+libx11-dev
+libxalan-c-dev
+libxerces-c-dev
+libxml2-dev libxml2-utils
+libxslt-dev xsltproc
+openjdk-11-jdk
+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
+libmono-system-windows-forms4.0-cil
diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt b/.gitlab/ci/docker/debian10/docker-clean
index e69de29..e69de29 100644
--- a/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt
+++ b/.gitlab/ci/docker/debian10/docker-clean
diff --git a/.gitlab/ci/docker/debian10/dpkg-exclude b/.gitlab/ci/docker/debian10/dpkg-exclude
new file mode 100644
index 0000000..60b6565
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/dpkg-exclude
@@ -0,0 +1,21 @@
+# Drop all man pages
+path-exclude=/usr/share/man/*
+
+# Drop all info pages
+path-exclude=/usr/share/info/*
+
+# Drop all README files except from the some packages
+path-exclude=/usr/**/*README*
+path-include=/usr/share/devscripts/templates/README.mk-build-deps
+path-include=/usr/share/equivs/template/debian/README.Debian.in
+
+# Drop all translations
+path-exclude=/usr/share/locale/*/LC_MESSAGES/*.mo
+
+# Drop all documentation ...
+path-exclude=/usr/share/doc/*
+path-exclude=/usr/share/doc-base/*
+path-exclude=/usr/share/gtk-doc/*
+
+# Per package excludes
+path-exclude=/usr/share/gnupg/help.*.txt
diff --git a/.gitlab/ci/docker/debian10/install_deps.sh b/.gitlab/ci/docker/debian10/install_deps.sh
index 486b2f7..a00e322 100755
--- a/.gitlab/ci/docker/debian10/install_deps.sh
+++ b/.gitlab/ci/docker/debian10/install_deps.sh
@@ -2,112 +2,8 @@
set -e
-apt-get update
+apt-get install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
-# Install build requirements.
-apt-get install -y \
- libssl-dev
-
-# Install development tools.
-apt-get install -y \
- g++ \
- curl \
- git
-
-# Install optional external build dependencies.
-apt-get install -y \
- libarchive-dev \
- libbz2-dev \
- libcurl4-gnutls-dev \
- libexpat1-dev \
- libjsoncpp-dev \
- liblzma-dev \
- libncurses-dev \
- librhash-dev \
- libuv1-dev \
- libzstd-dev \
- zlib1g-dev
-
-# 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 CTest.
-apt-get install -y \
- bzr bzr-xmloutput \
- cvs \
- subversion \
- mercurial
-
-# Install swift runtime deps.
-apt-get install -y \
- libncurses5
-
-# Packages needed to test find modules.
-apt-get install -y \
- alsa-utils \
- doxygen graphviz \
- freeglut3-dev \
- 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 \
- libgmock-dev \
- libgrpc++-dev libgrpc-dev \
- libgsl-dev \
- libgtest-dev \
- libgtk2.0-dev \
- libicu-dev \
- libinput-dev \
- libjpeg-dev \
- libjsoncpp-dev \
- liblapack-dev \
- liblzma-dev \
- libopenal-dev \
- libopenmpi-dev openmpi-bin \
- libosp-dev \
- libpng-dev \
- libpq-dev postgresql-server-dev-11 \
- libprotobuf-dev libprotobuf-c-dev libprotoc-dev protobuf-compiler protobuf-compiler-grpc \
- libsdl-dev \
- libsqlite3-dev \
- libtiff-dev \
- libuv1-dev \
- libx11-dev \
- libxalan-c-dev \
- libxerces-c-dev \
- libxml2-dev libxml2-utils \
- libxslt-dev xsltproc \
- openjdk-11-jdk \
- 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
echo 'e1aceec1d49ffa66e9059a52168a734999dcccc50164a60e2936649cae698f3e ironpython_2.7.10.deb' > ironpython.sha256sum
sha256sum --check ironpython.sha256sum
@@ -115,8 +11,5 @@ dpkg -i ironpython_2.7.10.deb
rm ironpython_2.7.10.deb ironpython.sha256sum
# Perforce
-curl -L -O https://www.perforce.com/downloads/perforce/r21.2/bin.linux26x86_64/helix-core-server.tgz
-tar -C /usr/local/bin -xvzf helix-core-server.tgz -- p4 p4d
-rm helix-core-server.tgz
-
-apt-get clean
+curl -L https://www.perforce.com/downloads/perforce/r21.2/bin.linux26x86_64/helix-core-server.tgz -o - \
+ | tar -C /usr/local/bin -xvzf - -- p4 p4d
diff --git a/.gitlab/ci/docker/debian10/install_iwyu.sh b/.gitlab/ci/docker/debian10/install_iwyu.sh
index 54d26ef..4814a71 100755
--- a/.gitlab/ci/docker/debian10/install_iwyu.sh
+++ b/.gitlab/ci/docker/debian10/install_iwyu.sh
@@ -3,16 +3,7 @@
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
+apt-get install -y $(grep '^[^#]\+$' /root/iwyu_packages.lst)
cd /root
git clone "https://github.com/include-what-you-use/include-what-you-use.git"
@@ -29,4 +20,4 @@ cmake -GNinja \
..
ninja
DESTDIR=/root/iwyu-destdir ninja install
-tar -C /root/iwyu-destdir -cf /root/iwyu.tar.gz .
+tar -C /root/iwyu-destdir -cf /root/iwyu.tar .
diff --git a/.gitlab/ci/docker/debian10/install_rvm.sh b/.gitlab/ci/docker/debian10/install_rvm.sh
index 0ebc746..c6fff70 100755
--- a/.gitlab/ci/docker/debian10/install_rvm.sh
+++ b/.gitlab/ci/docker/debian10/install_rvm.sh
@@ -2,11 +2,7 @@
set -e
-apt-get update
-apt-get install -y \
- curl \
- gnupg2 \
- procps
+apt-get install -y $(grep '^[^#]\+$' /root/rvm_packages.lst)
gpg2 --keyserver hkps://keyserver.ubuntu.com \
--recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 \
@@ -17,4 +13,8 @@ curl -sSL https://get.rvm.io | bash -s stable
# keep version in sync with `env_debian*_ninja.sh`
/usr/local/rvm/bin/rvm install ruby-2.7.0
-tar -C /usr/local -cf /root/rvm.tar rvm
+for p in archives examples gem-cache log src; do
+ touch /usr/local/rvm/${p}/.tar_exclude
+done
+
+tar -C /usr/local --exclude-tag-under=.tar_exclude -cf /root/rvm.tar rvm
diff --git a/.gitlab/ci/docker/debian10/iwyu_packages.lst b/.gitlab/ci/docker/debian10/iwyu_packages.lst
new file mode 100644
index 0000000..9e291c9
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/iwyu_packages.lst
@@ -0,0 +1,9 @@
+# Install development tools.
+clang-6.0
+libclang-6.0-dev
+llvm-6.0-dev
+libz-dev
+g++
+cmake
+ninja-build
+git
diff --git a/.gitlab/ci/docker/debian10/rvm_packages.lst b/.gitlab/ci/docker/debian10/rvm_packages.lst
new file mode 100644
index 0000000..80f079c
--- /dev/null
+++ b/.gitlab/ci/docker/debian10/rvm_packages.lst
@@ -0,0 +1,25 @@
+autoconf
+automake
+bison
+bzip2
+curl
+g++
+gawk
+gcc
+gnupg2
+libc6-dev
+libffi-dev
+libgdbm-dev
+libgmp-dev
+libncurses5-dev
+libreadline-dev
+libsqlite3-dev
+libssl-dev
+libtool
+libyaml-dev
+make
+patch
+pkg-config
+procps
+sqlite3
+zlib1g-dev
diff --git a/.gitlab/ci/docker/fedora36/Dockerfile b/.gitlab/ci/docker/fedora36/Dockerfile
deleted file mode 100644
index ea42561..0000000
--- a/.gitlab/ci/docker/fedora36/Dockerfile
+++ /dev/null
@@ -1,33 +0,0 @@
-FROM fedora:36 as rvm-build
-MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
-
-COPY install_rvm.sh /root/install_rvm.sh
-RUN sh /root/install_rvm.sh
-
-FROM fedora:36 AS clang-tidy-headers
-MAINTAINER Kyle Edwards <kyle.edwards@kitware.com>
-
-COPY install_clang_tidy_headers.sh /root/install_clang_tidy_headers.sh
-RUN sh /root/install_clang_tidy_headers.sh
-
-FROM fedora:36 AS iwyu
-MAINTAINER Kyle Edwards <kyle.edwards@kitware.com>
-
-COPY install_iwyu.sh /root/install_iwyu.sh
-RUN sh /root/install_iwyu.sh
-
-FROM fedora:36
-MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
-
-COPY install_deps.sh /root/install_deps.sh
-RUN sh /root/install_deps.sh
-
-COPY --from=rvm-build /root/rvm.tar /root/rvm.tar
-RUN tar -C /usr/local -xf /root/rvm.tar \
- && rm /root/rvm.tar
-COPY --from=clang-tidy-headers /root/clang-tidy-headers.tar /root/clang-tidy-headers.tar
-RUN tar -C /usr/include -xf /root/clang-tidy-headers.tar \
- && rm /root/clang-tidy-headers.tar
-COPY --from=iwyu /root/iwyu.tar /root/iwyu.tar
-RUN tar -C / -xf /root/iwyu.tar \
- && rm /root/iwyu.tar
diff --git a/.gitlab/ci/docker/fedora36/install_deps.sh b/.gitlab/ci/docker/fedora36/install_deps.sh
deleted file mode 100755
index f117888..0000000
--- a/.gitlab/ci/docker/fedora36/install_deps.sh
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/bin/sh
-
-set -e
-
-# Install build requirements.
-dnf install --setopt=install_weak_deps=False -y \
- ncurses-devel \
- openssl-devel \
- qt5-qtbase-devel \
- qt6-qtbase-devel
-
-# Install development tools.
-dnf install --setopt=install_weak_deps=False -y \
- clang-tools-extra \
- compiler-rt \
- gcc-c++ \
- git-core \
- make
-
-# Install optional external build dependencies.
-dnf install --setopt=install_weak_deps=False -y \
- bzip2-devel \
- expat-devel \
- jsoncpp-devel \
- libarchive-devel \
- libcurl-devel \
- libuv-devel \
- libuv-devel \
- libzstd-devel \
- rhash-devel \
- xz-devel \
- zlib-devel
-
-# Install documentation tools.
-dnf install --setopt=install_weak_deps=False -y \
- python3-sphinx \
- texinfo \
- qt5-qttools-devel \
- qt6-qttools-devel
-
-# Install lint tools.
-dnf install --setopt=install_weak_deps=False -y \
- clang-analyzer \
- codespell
-
-# Tools needed for the test suite.
-dnf install --setopt=install_weak_deps=False -y \
- findutils \
- file \
- jq \
- which
-
-# Packages needed to test CTest.
-dnf install --setopt=install_weak_deps=False -y \
- breezy \
- subversion \
- mercurial
-
-# Packages needed to test CPack.
-dnf install --setopt=install_weak_deps=False -y \
- rpm-build
-
-# 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 \
- freeglut-devel \
- freetype-devel \
- gdal-devel \
- gettext \
- giflib-devel \
- glew-devel \
- gmock \
- gnutls-devel \
- grpc-devel grpc-plugins \
- gsl-devel \
- gtest-devel \
- gtk2-devel \
- java-11-openjdk-devel \
- jsoncpp-devel \
- lapack-devel \
- libarchive-devel \
- libcurl-devel \
- libicu-devel \
- libinput-devel systemd-devel \
- libjpeg-turbo-devel \
- libpng-devel \
- opensp-devel \
- postgresql-server-devel \
- libtiff-devel \
- libuv-devel \
- libxml2-devel \
- libxslt-devel \
- mpich-devel \
- openal-soft-devel \
- openmpi-devel \
- patch \
- perl \
- protobuf-devel protobuf-c-devel protobuf-lite-devel \
- pypy2 pypy2-devel \
- pypy3 pypy3-devel \
- python2 python2-devel \
- 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
-
-# Fedora no longer packages python2 numpy.
-curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py
-python2 get-pip.py
-rm get-pip.py
-pip2.7 install numpy
-
-# Perforce
-curl -L -O https://www.perforce.com/downloads/perforce/r21.2/bin.linux26x86_64/helix-core-server.tgz
-tar -C /usr/local/bin -xvzf helix-core-server.tgz -- p4 p4d
-rm helix-core-server.tgz
diff --git a/.gitlab/ci/docker/fedora36/install_rvm.sh b/.gitlab/ci/docker/fedora36/install_rvm.sh
deleted file mode 100755
index 0011f87..0000000
--- a/.gitlab/ci/docker/fedora36/install_rvm.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-set -e
-
-gpg2 --keyserver hkps://keyserver.ubuntu.com \
- --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 \
- 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-
-dnf install --setopt=install_weak_deps=False -y \
- findutils \
- procps \
- which
-
-curl -sSL https://get.rvm.io | bash -s stable
-
-# keep version in sync with `env_fedora*_makefiles.cmake`
-/usr/local/rvm/bin/rvm install ruby-3.0.4
-
-tar -C /usr/local -cf /root/rvm.tar rvm
diff --git a/.gitlab/ci/docker/fedora37/Dockerfile b/.gitlab/ci/docker/fedora37/Dockerfile
new file mode 100644
index 0000000..b36a17e
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/Dockerfile
@@ -0,0 +1,73 @@
+# syntax=docker/dockerfile:1
+
+ARG BASE_IMAGE=fedora:37
+
+FROM ${BASE_IMAGE} AS dnf-cache
+# Populate DNF cache w/ the fresh metadata and prefetch packages.
+RUN --mount=type=bind,source=clang_tidy_headers_packages.lst,target=/root/clang_tidy_headers_packages.lst \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=bind,source=iwyu_packages.lst,target=/root/iwyu_packages.lst \
+ --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ dnf install \
+ --setopt=install_weak_deps=False \
+ --setopt=fastestmirror=True \
+ --setopt=max_parallel_downloads=10 \
+ --downloadonly \
+ -y \
+ $(grep -h '^[^#]\+$' /root/*.lst)
+
+
+FROM ${BASE_IMAGE} AS rvm-build
+LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+
+RUN --mount=type=bind,source=install_rvm.sh,target=/root/install_rvm.sh \
+ --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
+ --mount=type=cache,from=dnf-cache,source=/var/cache/dnf,target=/var/cache/dnf,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_rvm.sh
+
+
+FROM ${BASE_IMAGE} AS clang-tidy-headers
+LABEL maintainer="Kyle Edwards <kyle.edwards@kitware.com>"
+
+RUN --mount=type=bind,source=install_clang_tidy_headers.sh,target=/root/install_clang_tidy_headers.sh \
+ --mount=type=bind,source=clang_tidy_headers_packages.lst,target=/root/clang_tidy_headers_packages.lst \
+ --mount=type=cache,from=dnf-cache,source=/var/cache/dnf,target=/var/cache/dnf,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_clang_tidy_headers.sh
+
+
+FROM ${BASE_IMAGE} AS iwyu-build
+LABEL maintainer="Kyle Edwards <kyle.edwards@kitware.com>"
+
+RUN --mount=type=bind,source=install_iwyu.sh,target=/root/install_iwyu.sh \
+ --mount=type=bind,source=iwyu_packages.lst,target=/root/iwyu_packages.lst \
+ --mount=type=cache,from=dnf-cache,source=/var/cache/dnf,target=/var/cache/dnf,sharing=private \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_iwyu.sh
+
+
+FROM ${BASE_IMAGE}
+LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+
+RUN --mount=type=bind,source=install_deps.sh,target=/root/install_deps.sh \
+ --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+ --mount=type=cache,from=dnf-cache,source=/var/cache/dnf,target=/var/cache/dnf,sharing=private \
+ --mount=type=cache,target=/var/cache/pip \
+ --mount=type=tmpfs,target=/var/log \
+ --mount=type=tmpfs,target=/tmp \
+ sh /root/install_deps.sh
+
+RUN --mount=type=bind,from=rvm-build,source=/root,target=/root \
+ tar -C /usr/local -xf /root/rvm.tar
+
+RUN --mount=type=bind,from=clang-tidy-headers,source=/root,target=/root \
+ tar -C /usr/include -xf /root/clang-tidy-headers.tar
+
+RUN --mount=type=bind,from=iwyu-build,source=/root,target=/root \
+ tar -C / -xf /root/iwyu.tar
diff --git a/.gitlab/ci/docker/fedora37/clang_tidy_headers_packages.lst b/.gitlab/ci/docker/fedora37/clang_tidy_headers_packages.lst
new file mode 100644
index 0000000..fe86105
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/clang_tidy_headers_packages.lst
@@ -0,0 +1,4 @@
+dnf-command(download)
+rpm-build
+python3-devel
+clang-tools-extra
diff --git a/.gitlab/ci/docker/fedora37/deps_packages.lst b/.gitlab/ci/docker/fedora37/deps_packages.lst
new file mode 100644
index 0000000..9ce8007
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/deps_packages.lst
@@ -0,0 +1,110 @@
+# Install build requirements.
+ncurses-devel
+openssl-devel
+qt5-qtbase-devel
+qt6-qtbase-devel
+
+# Install development tools.
+clang
+clang-tools-extra
+compiler-rt
+flang
+flang-devel
+gcc-c++
+git-core
+make
+
+# Install optional external build dependencies.
+bzip2-devel
+expat-devel
+jsoncpp-devel
+libarchive-devel
+libcurl-devel
+libuv-devel
+libuv-devel
+libzstd-devel
+rhash-devel
+xz-devel
+zlib-devel
+
+# Install documentation tools.
+python3-sphinx
+texinfo
+qt5-qttools-devel
+qt6-qttools-devel
+
+# Install lint tools.
+clang-analyzer
+codespell
+
+# Tools needed for the test suite.
+findutils
+file
+jq
+which
+
+# Packages needed to test CTest.
+breezy
+subversion
+mercurial
+
+# Packages needed to test CPack.
+rpm-build
+
+# Packages needed to test find modules.
+alsa-lib-devel
+blas-devel
+boost-devel boost-python3-devel
+bzip2-devel
+cups-devel
+DevIL-devel
+doxygen
+expat-devel
+fontconfig-devel
+freeglut-devel
+freetype-devel
+gdal-devel
+gettext
+giflib-devel
+glew-devel
+gmock
+gnutls-devel
+grpc-devel grpc-plugins
+gsl-devel
+gtest-devel
+gtk2-devel
+ImageMagick-c++-devel
+java-11-openjdk-devel
+jsoncpp-devel
+lapack-devel
+libarchive-devel
+libcurl-devel
+libicu-devel
+libinput-devel systemd-devel
+libjpeg-turbo-devel
+libpng-devel
+opensp-devel
+postgresql-server-devel
+libtiff-devel
+libuv-devel
+libxml2-devel
+libxslt-devel
+mpich-devel
+openal-soft-devel
+openmpi-devel
+patch
+perl
+protobuf-devel protobuf-c-devel protobuf-lite-devel
+pypy2 pypy2-devel
+pypy3 pypy3-devel
+python2 python2-devel
+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
diff --git a/.gitlab/ci/docker/fedora36/install_clang_tidy_headers.sh b/.gitlab/ci/docker/fedora37/install_clang_tidy_headers.sh
index b9883f4..200fa1e 100755
--- a/.gitlab/ci/docker/fedora36/install_clang_tidy_headers.sh
+++ b/.gitlab/ci/docker/fedora37/install_clang_tidy_headers.sh
@@ -4,11 +4,13 @@ set -e
# Packages for building the clang-tidy plugin.
# TODO: Upstream this as a proper Fedora package.
-dnf install --setopt=install_weak_deps=False -y \
- 'dnf-command(download)' \
- rpm-build \
- python3-devel \
- clang-tools-extra
+dnf install \
+ --setopt=install_weak_deps=False \
+ --setopt=fastestmirror=True \
+ --setopt=max_parallel_downloads=10 \
+ -y \
+ $(grep '^[^#]\+$' /root/clang_tidy_headers_packages.lst)
+
clang_source_rpm=$(rpm -q --queryformat '%{SOURCERPM}' clang-tools-extra)
clang_version=$(rpm -q --queryformat '%{VERSION}' clang-tools-extra)
dnf download --source -y clang
diff --git a/.gitlab/ci/docker/fedora37/install_deps.sh b/.gitlab/ci/docker/fedora37/install_deps.sh
new file mode 100755
index 0000000..cd2701e
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/install_deps.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+set -e
+
+dnf install \
+ --setopt=install_weak_deps=False \
+ --setopt=fastestmirror=True \
+ --setopt=max_parallel_downloads=10 \
+ -y \
+ $(grep '^[^#]\+$' /root/deps_packages.lst)
+
+# Fedora no longer packages python2 numpy.
+curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o - | python2
+pip2.7 install --disable-pip-version-check --no-input --no-compile --cache-dir /var/cache/pip numpy
+
+# Remove demos and Python2 tests
+for p in Demo test; do
+ rm -rf /usr/lib64/python2.7/${p}
+done
+
+# Remove tests for numpy
+for v in 2.7 3.11; do
+ find /usr/lib64/python${v}/site-packages/numpy -type d -a -name tests -exec rm -rf {} +
+done
+
+# Remove some other packages tests
+find /usr/lib64/python3.11/site-packages/breezy -type d -a -name tests -exec rm -rf {} +
+
+# Perforce
+curl -L https://www.perforce.com/downloads/perforce/r21.2/bin.linux26x86_64/helix-core-server.tgz -o - \
+ | tar -C /usr/local/bin -xvzf - -- p4 p4d
diff --git a/.gitlab/ci/docker/fedora36/install_iwyu.sh b/.gitlab/ci/docker/fedora37/install_iwyu.sh
index 714bcc0..684e355 100755
--- a/.gitlab/ci/docker/fedora36/install_iwyu.sh
+++ b/.gitlab/ci/docker/fedora37/install_iwyu.sh
@@ -3,14 +3,12 @@
set -e
# Install development tools.
-dnf install --setopt=install_weak_deps=False -y \
- clang-devel \
- llvm-devel \
- zlib-devel \
- g++ \
- cmake \
- ninja-build \
- git
+dnf install \
+ --setopt=install_weak_deps=False \
+ --setopt=fastestmirror=True \
+ --setopt=max_parallel_downloads=10 \
+ -y \
+ $(grep '^[^#]\+$' /root/iwyu_packages.lst)
cd /root
git clone "https://github.com/include-what-you-use/include-what-you-use.git"
diff --git a/.gitlab/ci/docker/fedora37/install_rvm.sh b/.gitlab/ci/docker/fedora37/install_rvm.sh
new file mode 100755
index 0000000..10e7545
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/install_rvm.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+dnf install \
+ --setopt=install_weak_deps=False \
+ --setopt=fastestmirror=True \
+ --setopt=max_parallel_downloads=10 \
+ -y \
+ $(grep '^[^#]\+$' /root/rvm_packages.lst)
+
+gpg2 --keyserver hkps://keyserver.ubuntu.com \
+ --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 \
+ 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
+
+curl -sSL https://get.rvm.io | bash -s stable
+
+# keep version in sync with `env_fedora*_makefiles.cmake`
+/usr/local/rvm/bin/rvm install ruby-3.0.4
+
+for p in archives examples gem-cache log src; do
+ touch /usr/local/rvm/${p}/.tar_exclude
+done
+
+tar -C /usr/local --exclude-tag-under=.tar_exclude -cf /root/rvm.tar rvm
diff --git a/.gitlab/ci/docker/fedora37/iwyu_packages.lst b/.gitlab/ci/docker/fedora37/iwyu_packages.lst
new file mode 100644
index 0000000..e3551bd
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/iwyu_packages.lst
@@ -0,0 +1,7 @@
+clang-devel
+llvm-devel
+zlib-devel
+g++
+cmake
+ninja-build
+git
diff --git a/.gitlab/ci/docker/fedora37/rvm_packages.lst b/.gitlab/ci/docker/fedora37/rvm_packages.lst
new file mode 100644
index 0000000..1dc852e
--- /dev/null
+++ b/.gitlab/ci/docker/fedora37/rvm_packages.lst
@@ -0,0 +1,18 @@
+autoconf
+automake
+bison
+bzip2
+findutils
+gcc-c++
+glibc-devel
+libffi-devel
+libtool
+libyaml-devel
+make
+openssl-devel
+patch
+procps
+readline-devel
+sqlite-devel
+which
+zlib-devel
diff --git a/.gitlab/ci/docker/nvhpc22.11/Dockerfile b/.gitlab/ci/docker/nvhpc22.11/Dockerfile
new file mode 100644
index 0000000..078ae37
--- /dev/null
+++ b/.gitlab/ci/docker/nvhpc22.11/Dockerfile
@@ -0,0 +1,6 @@
+# https://catalog.ngc.nvidia.com/orgs/nvidia/containers/nvhpc/tags
+FROM kitware/nvidia-nvhpc:22.11-devel-cuda_multi-ubuntu22.04
+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/nvhpc22.11/install_deps.sh b/.gitlab/ci/docker/nvhpc22.11/install_deps.sh
new file mode 100755
index 0000000..51ee410
--- /dev/null
+++ b/.gitlab/ci/docker/nvhpc22.11/install_deps.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+
+apt-get update
+
+# Install development tools.
+apt-get install -y \
+ curl
+
+apt-get clean
diff --git a/.gitlab/ci/env_fedora36_asan.sh b/.gitlab/ci/env_fedora37_asan.sh
index e976486..e976486 100644
--- a/.gitlab/ci/env_fedora36_asan.sh
+++ b/.gitlab/ci/env_fedora37_asan.sh
diff --git a/.gitlab/ci/env_fedora36_clang_analyzer.sh b/.gitlab/ci/env_fedora37_clang_analyzer.sh
index d732c0b..d732c0b 100644
--- a/.gitlab/ci/env_fedora36_clang_analyzer.sh
+++ b/.gitlab/ci/env_fedora37_clang_analyzer.sh
diff --git a/.gitlab/ci/env_fedora37_common_clang.sh b/.gitlab/ci/env_fedora37_common_clang.sh
new file mode 100644
index 0000000..b03b757
--- /dev/null
+++ b/.gitlab/ci/env_fedora37_common_clang.sh
@@ -0,0 +1,4 @@
+export CC=/usr/bin/clang-15
+export CXX=/usr/bin/clang++-15
+export FC=/usr/bin/flang-new
+export FFLAGS=-flang-experimental-exec
diff --git a/.gitlab/ci/env_fedora36_extdeps.sh b/.gitlab/ci/env_fedora37_extdeps.sh
index 7076e18..7076e18 100644
--- a/.gitlab/ci/env_fedora36_extdeps.sh
+++ b/.gitlab/ci/env_fedora37_extdeps.sh
diff --git a/.gitlab/ci/env_fedora36_makefiles.cmake b/.gitlab/ci/env_fedora37_makefiles.cmake
index 2bcb6d0..2bcb6d0 100644
--- a/.gitlab/ci/env_fedora36_makefiles.cmake
+++ b/.gitlab/ci/env_fedora37_makefiles.cmake
diff --git a/.gitlab/ci/env_fedora36_ninja_multi.sh b/.gitlab/ci/env_fedora37_makefiles.sh
index 217ff30..217ff30 100644
--- a/.gitlab/ci/env_fedora36_ninja_multi.sh
+++ b/.gitlab/ci/env_fedora37_makefiles.sh
diff --git a/.gitlab/ci/env_fedora37_makefiles_clang.sh b/.gitlab/ci/env_fedora37_makefiles_clang.sh
new file mode 100644
index 0000000..9ff1d84
--- /dev/null
+++ b/.gitlab/ci/env_fedora37_makefiles_clang.sh
@@ -0,0 +1 @@
+. .gitlab/ci/env_fedora37_common_clang.sh
diff --git a/.gitlab/ci/env_fedora36_ninja.sh b/.gitlab/ci/env_fedora37_ninja.sh
index 217ff30..217ff30 100644
--- a/.gitlab/ci/env_fedora36_ninja.sh
+++ b/.gitlab/ci/env_fedora37_ninja.sh
diff --git a/.gitlab/ci/env_fedora37_ninja_clang.sh b/.gitlab/ci/env_fedora37_ninja_clang.sh
new file mode 100644
index 0000000..9ff1d84
--- /dev/null
+++ b/.gitlab/ci/env_fedora37_ninja_clang.sh
@@ -0,0 +1 @@
+. .gitlab/ci/env_fedora37_common_clang.sh
diff --git a/.gitlab/ci/env_fedora36_makefiles.sh b/.gitlab/ci/env_fedora37_ninja_multi.sh
index 217ff30..217ff30 100644
--- a/.gitlab/ci/env_fedora36_makefiles.sh
+++ b/.gitlab/ci/env_fedora37_ninja_multi.sh
diff --git a/.gitlab/ci/env_macos_arm64_ninja.sh b/.gitlab/ci/env_macos_arm64_ninja.sh
new file mode 100644
index 0000000..f8d459b
--- /dev/null
+++ b/.gitlab/ci/env_macos_arm64_ninja.sh
@@ -0,0 +1 @@
+. .gitlab/ci/openmp-env.sh
diff --git a/.gitlab/ci/env_macos_x86_64_makefiles.sh b/.gitlab/ci/env_macos_x86_64_makefiles.sh
index 217ff30..7496372 100644
--- a/.gitlab/ci/env_macos_x86_64_makefiles.sh
+++ b/.gitlab/ci/env_macos_x86_64_makefiles.sh
@@ -1,3 +1,4 @@
+. .gitlab/ci/openmp-env.sh
if test "$CMAKE_CI_NIGHTLY" = "true"; then
source .gitlab/ci/ispc-env.sh
fi
diff --git a/.gitlab/ci/env_macos_x86_64_ninja.sh b/.gitlab/ci/env_macos_x86_64_ninja.sh
index 217ff30..7496372 100644
--- a/.gitlab/ci/env_macos_x86_64_ninja.sh
+++ b/.gitlab/ci/env_macos_x86_64_ninja.sh
@@ -1,3 +1,4 @@
+. .gitlab/ci/openmp-env.sh
if test "$CMAKE_CI_NIGHTLY" = "true"; then
source .gitlab/ci/ispc-env.sh
fi
diff --git a/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1 b/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1
new file mode 100755
index 0000000..e2d573e
--- /dev/null
+++ b/.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps1
@@ -0,0 +1,3 @@
+$pwdpath = $pwd.Path
+& "$pwsh" -File ".gitlab/ci/mingw.ps1"
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\mingw\bin;$env:PATH"
diff --git a/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1 b/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1
new file mode 100755
index 0000000..6eccb72
--- /dev/null
+++ b/.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps1
@@ -0,0 +1,5 @@
+$pwdpath = $pwd.Path
+& "$pwsh" -File ".gitlab/ci/mingw.ps1"
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\mingw\msys\1.0\bin;$pwdpath\.gitlab\mingw\bin;$env:PATH"
+$env:MSYSTEM = 'MINGW32'
+$env:MAKE_MODE = 'unix'
diff --git a/.gitlab/ci/env_nvhpc_ninja.sh b/.gitlab/ci/env_nvhpc_ninja.sh
new file mode 100644
index 0000000..687403d
--- /dev/null
+++ b/.gitlab/ci/env_nvhpc_ninja.sh
@@ -0,0 +1,5 @@
+export CC=nvc
+export CXX=nvc++
+export FC=nvfortran
+export CUDACXX=nvcc
+export CUDAHOSTCXX=nvc++
diff --git a/.gitlab/ci/mingw.ps1 b/.gitlab/ci/mingw.ps1
new file mode 100755
index 0000000..a1b5b11
--- /dev/null
+++ b/.gitlab/ci/mingw.ps1
@@ -0,0 +1,25 @@
+$erroractionpreference = "stop"
+
+if ("$env:CMAKE_CONFIGURATION".Contains("mingw_osdn_io")) {
+ $filename = "mingw.osdn.io-2022-10-03"
+ $sha256sum = "4DCB8C351D8D855F7D3DFC2863A235042BF3DB6E69EA0BAE51FF9378189345CD"
+} else {
+ throw ('unknown CMAKE_CONFIGURATION: ' + "$env:CMAKE_CONFIGURATION")
+}
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://cmake.org/files/dependencies/$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\mingw"
+Remove-Item "$outdir\$tarball"
+
+"$outdir/mingw /mingw" -replace '\\', '/' | Out-File -FilePath "$outdir\mingw\msys\1.0\etc\fstab" -Encoding ASCII
diff --git a/.gitlab/ci/openmp-env.sh b/.gitlab/ci/openmp-env.sh
new file mode 100644
index 0000000..82dac5b
--- /dev/null
+++ b/.gitlab/ci/openmp-env.sh
@@ -0,0 +1,3 @@
+.gitlab/ci/openmp.sh
+export CMAKE_PREFIX_PATH=$PWD/.gitlab/openmp${CMAKE_PREFIX_PATH:+:$CMAKE_PREFIX_PATH}
+export DYLD_LIBRARY_PATH=$PWD/.gitlab/openmp/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}
diff --git a/.gitlab/ci/openmp.sh b/.gitlab/ci/openmp.sh
new file mode 100755
index 0000000..f411338
--- /dev/null
+++ b/.gitlab/ci/openmp.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+baseurl="https://cmake.org/files/dependencies/openmp"
+
+case "$(uname -s)-$(uname -m)" in
+ Darwin-*)
+ shatool="shasum -a 256"
+ sha256sum="6eef660db7a085a04f87e4aac79da9f37d26ff0fb17c8781d3a21bd5244997e9"
+ filename="openmp-12.0.1-darwin20-Release"
+ # tarball contains usr/local/
+ strip_components=--strip-components=2
+ ;;
+ *)
+ echo "Unrecognized platform $(uname -s)-$(uname -m)"
+ exit 1
+ ;;
+esac
+readonly shatool
+readonly sha256sum
+
+readonly tarball="$filename.tar.gz"
+
+cd .gitlab
+mkdir -p openmp
+
+echo "$sha256sum $tarball" > openmp.sha256sum
+curl -OL "$baseurl/$tarball"
+$shatool --check openmp.sha256sum
+tar -C openmp $strip_components -xzf $tarball
+rm $tarball openmp.sha256sum
diff --git a/.gitlab/ci/package_info.cmake.in b/.gitlab/ci/package_info.cmake.in
new file mode 100644
index 0000000..f9a5bb7
--- /dev/null
+++ b/.gitlab/ci/package_info.cmake.in
@@ -0,0 +1 @@
+set(CPACK_PACKAGE_FILE_NAME "@CPACK_PACKAGE_FILE_NAME@")
diff --git a/.gitlab/ci/package_macos.sh b/.gitlab/ci/package_macos.sh
new file mode 100644
index 0000000..7625c5d
--- /dev/null
+++ b/.gitlab/ci/package_macos.sh
@@ -0,0 +1,12 @@
+cd build
+cpack -G TGZ
+cpack -G DragNDrop
+
+case "$CMAKE_CI_PACKAGE" in
+ dev)
+ ;;
+ *)
+ mkdir -p unsigned
+ mv cmake-*-macos*-universal.* unsigned/
+ ;;
+esac
diff --git a/.gitlab/ci/package_windows.ps1 b/.gitlab/ci/package_windows.ps1
new file mode 100755
index 0000000..9ec2942
--- /dev/null
+++ b/.gitlab/ci/package_windows.ps1
@@ -0,0 +1,7 @@
+if (Test-Path -Path "build/ci_package_info.cmake" -PathType Leaf) {
+ cmake -P .gitlab/ci/package_windows_build.cmake
+} else {
+ cd build
+ cpack -G ZIP
+ cpack -G WIX
+}
diff --git a/.gitlab/ci/package_windows_build.cmake b/.gitlab/ci/package_windows_build.cmake
new file mode 100644
index 0000000..feb379c
--- /dev/null
+++ b/.gitlab/ci/package_windows_build.cmake
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.24)
+include(build/ci_package_info.cmake)
+
+set(build "${CMAKE_CURRENT_BINARY_DIR}/build")
+
+file(GLOB paths RELATIVE "${CMAKE_CURRENT_BINARY_DIR}"
+ # Allow CPack to find CMAKE_ROOT.
+ "${build}/CMakeFiles/CMakeSourceDir.txt"
+
+ # We need the main binaries.
+ "${build}/bin"
+
+ # Pass through the documentation.
+ "${build}/install-doc"
+
+ # CPack configuration.
+ "${build}/CPackConfig.cmake"
+ "${build}/CMakeCPackOptions.cmake"
+ "${build}/Source/QtDialog/QtDialogCPack.cmake"
+
+ # CPack/IFW packaging files.
+ "${build}/CMake*.qs"
+
+ # CPack/WIX packaging files.
+ "${build}/Utilities/Release/WiX/custom_action_dll*.wxs"
+ "${build}/Utilities/Release/WiX/CustomAction/CMakeWiXCustomActions.*"
+ )
+
+file(GLOB_RECURSE paths_recurse RELATIVE "${CMAKE_CURRENT_BINARY_DIR}"
+ # Install rules.
+ "${build}/cmake_install.cmake"
+ "${build}/*/cmake_install.cmake"
+ )
+
+# Create a "package" containing the build-tree files needed to build a package.
+file(MAKE_DIRECTORY build/unsigned)
+file(ARCHIVE_CREATE
+ OUTPUT build/unsigned/${CPACK_PACKAGE_FILE_NAME}.build.zip
+ PATHS ${paths} ${paths_recurse}
+ FORMAT zip
+ )
diff --git a/.gitlab/ci/post_build.ps1 b/.gitlab/ci/post_build.ps1
new file mode 100755
index 0000000..fbd8ae8
--- /dev/null
+++ b/.gitlab/ci/post_build.ps1
@@ -0,0 +1,4 @@
+$pwsh = [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName
+if (Test-Path -Path ".gitlab/ci/post_build_$env:CMAKE_CONFIGURATION.ps1" -PathType Leaf) {
+ . ".gitlab/ci/post_build_$env:CMAKE_CONFIGURATION.ps1"
+}
diff --git a/.gitlab/ci/post_build.sh b/.gitlab/ci/post_build.sh
new file mode 100755
index 0000000..0edd9f6
--- /dev/null
+++ b/.gitlab/ci/post_build.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+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/post_build_${CMAKE_CONFIGURATION}.sh"; then
+ source ".gitlab/ci/post_build_${CMAKE_CONFIGURATION}.sh"
+fi
diff --git a/.gitlab/ci/post_build_macos10.10_package.sh b/.gitlab/ci/post_build_macos10.10_package.sh
new file mode 100644
index 0000000..3b7bc72
--- /dev/null
+++ b/.gitlab/ci/post_build_macos10.10_package.sh
@@ -0,0 +1 @@
+. .gitlab/ci/package_macos.sh
diff --git a/.gitlab/ci/post_build_macos_package.sh b/.gitlab/ci/post_build_macos_package.sh
new file mode 100644
index 0000000..3b7bc72
--- /dev/null
+++ b/.gitlab/ci/post_build_macos_package.sh
@@ -0,0 +1 @@
+. .gitlab/ci/package_macos.sh
diff --git a/.gitlab/ci/post_build_windows_arm64_package.ps1 b/.gitlab/ci/post_build_windows_arm64_package.ps1
new file mode 100755
index 0000000..f98d995
--- /dev/null
+++ b/.gitlab/ci/post_build_windows_arm64_package.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/package_windows.ps1
diff --git a/.gitlab/ci/post_build_windows_i386_package.ps1 b/.gitlab/ci/post_build_windows_i386_package.ps1
new file mode 100755
index 0000000..f98d995
--- /dev/null
+++ b/.gitlab/ci/post_build_windows_i386_package.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/package_windows.ps1
diff --git a/.gitlab/ci/post_build_windows_x86_64_package.ps1 b/.gitlab/ci/post_build_windows_x86_64_package.ps1
new file mode 100755
index 0000000..f98d995
--- /dev/null
+++ b/.gitlab/ci/post_build_windows_x86_64_package.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/package_windows.ps1
diff --git a/.gitlab/ci/pre_build.ps1 b/.gitlab/ci/pre_build.ps1
new file mode 100755
index 0000000..3a56687
--- /dev/null
+++ b/.gitlab/ci/pre_build.ps1
@@ -0,0 +1,4 @@
+$pwsh = [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName
+if (Test-Path -Path ".gitlab/ci/pre_build_$env:CMAKE_CONFIGURATION.ps1" -PathType Leaf) {
+ . ".gitlab/ci/pre_build_$env:CMAKE_CONFIGURATION.ps1"
+}
diff --git a/.gitlab/ci/pre_build.sh b/.gitlab/ci/pre_build.sh
new file mode 100755
index 0000000..7ff6a69
--- /dev/null
+++ b/.gitlab/ci/pre_build.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+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/pre_build_${CMAKE_CONFIGURATION}.sh"; then
+ source ".gitlab/ci/pre_build_${CMAKE_CONFIGURATION}.sh"
+fi
diff --git a/.gitlab/ci/pre_build_fedora37_tidy.sh b/.gitlab/ci/pre_build_fedora37_tidy.sh
new file mode 100644
index 0000000..7580ef1
--- /dev/null
+++ b/.gitlab/ci/pre_build_fedora37_tidy.sh
@@ -0,0 +1,9 @@
+cmake \
+ -G Ninja \
+ -S Utilities/ClangTidyModule \
+ -B Utilities/ClangTidyModule/build \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DRUN_TESTS=ON \
+ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
+cmake --build Utilities/ClangTidyModule/build
+ctest --test-dir Utilities/ClangTidyModule/build --output-on-failure
diff --git a/.gitlab/ci/python-env.ps1 b/.gitlab/ci/python-env.ps1
new file mode 100755
index 0000000..4e897d8
--- /dev/null
+++ b/.gitlab/ci/python-env.ps1
@@ -0,0 +1,4 @@
+$pwdpath = $pwd.Path
+cmake -P .gitlab/ci/download_python3.cmake
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\python3;$env:PATH"
+python --version
diff --git a/.gitlab/ci/qt-env.ps1 b/.gitlab/ci/qt-env.ps1
new file mode 100755
index 0000000..7eff55f
--- /dev/null
+++ b/.gitlab/ci/qt-env.ps1
@@ -0,0 +1,10 @@
+if ("$env:PROCESSOR_ARCHITECTURE" -eq "AMD64") {
+ $pwdpath = $pwd.Path
+ cmake -P .gitlab/ci/download_qt.cmake
+ Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\qt\bin;$env:PATH"
+ qmake -v
+} elseif ("$env:PROCESSOR_ARCHITECTURE" -eq "ARM64") {
+ # Qt host tools are not yet available natively on windows-arm64.
+} else {
+ throw ('unknown PROCESSOR_ARCHITECTURE: ' + "$env:PROCESSOR_ARCHITECTURE")
+}
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 28be5d3..9a53401 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -5,7 +5,7 @@
### Release
.linux_prep_source:
- image: "fedora:36"
+ image: "fedora:37"
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -45,7 +45,7 @@
### Debian
.debian10:
- image: "kitware/cmake:ci-debian10-x86_64-2022-08-30"
+ image: "kitware/cmake:ci-debian10-x86_64-2023-02-07"
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -60,7 +60,7 @@
CMAKE_CI_NO_INSTALL: 1
.debian10_aarch64:
- image: "kitware/cmake:ci-debian10-aarch64-2022-08-30"
+ image: "kitware/cmake:ci-debian10-aarch64-2023-02-07"
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -68,8 +68,8 @@
### Fedora
-.fedora36:
- image: "kitware/cmake:ci-fedora36-x86_64-2022-10-04"
+.fedora37:
+ image: "kitware/cmake:ci-fedora37-x86_64-2023-02-07"
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
@@ -77,37 +77,37 @@
#### Lint builds
-.fedora36_tidy:
- extends: .fedora36
+.fedora37_tidy:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_tidy
+ CMAKE_CONFIGURATION: fedora37_tidy
CTEST_NO_WARNINGS_ALLOWED: 1
CMAKE_CI_NO_INSTALL: 1
-.fedora36_clang_analyzer:
- extends: .fedora36
+.fedora37_clang_analyzer:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_clang_analyzer
+ CMAKE_CONFIGURATION: fedora37_clang_analyzer
CMAKE_CI_BUILD_TYPE: Debug
CTEST_NO_WARNINGS_ALLOWED: 1
CMAKE_CI_NO_INSTALL: 1
-.fedora36_sphinx:
- extends: .fedora36
+.fedora37_sphinx:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_sphinx
+ CMAKE_CONFIGURATION: fedora37_sphinx
CTEST_NO_WARNINGS_ALLOWED: 1
CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx"
CMAKE_CI_NO_INSTALL: 1
-.fedora36_sphinx_package:
- extends: .fedora36
+.fedora37_sphinx_package:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_sphinx_package
+ CMAKE_CONFIGURATION: fedora37_sphinx_package
CTEST_SOURCE_SUBDIRECTORY: "Utilities/Sphinx"
#### Build and test
@@ -153,35 +153,35 @@
CMAKE_CI_BUILD_TYPE: Release
CTEST_NO_WARNINGS_ALLOWED: 1
-.fedora36_extdeps:
- extends: .fedora36
+.fedora37_extdeps:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_extdeps
+ CMAKE_CONFIGURATION: fedora37_extdeps
CMAKE_CI_BUILD_TYPE: Release
CTEST_NO_WARNINGS_ALLOWED: 1
-.fedora36_ninja:
- extends: .fedora36
+.fedora37_ninja:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_ninja
+ CMAKE_CONFIGURATION: fedora37_ninja
CMAKE_CI_BUILD_TYPE: Release
CTEST_NO_WARNINGS_ALLOWED: 1
-.fedora36_ninja_multi:
- extends: .fedora36
+.fedora37_ninja_multi:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_ninja_multi
+ CMAKE_CONFIGURATION: fedora37_ninja_multi
CTEST_NO_WARNINGS_ALLOWED: 1
CMAKE_GENERATOR: "Ninja Multi-Config"
-.fedora36_makefiles:
- extends: .fedora36
+.fedora37_makefiles:
+ extends: .fedora37
variables:
- CMAKE_CONFIGURATION: fedora36_makefiles
+ CMAKE_CONFIGURATION: fedora37_makefiles
CTEST_NO_WARNINGS_ALLOWED: 1
CMAKE_GENERATOR: "Unix Makefiles"
@@ -200,6 +200,19 @@
variables:
CMAKE_CONFIGURATION: debian10_ninja_clang
+.fedora37_makefiles_clang:
+ extends: .fedora37
+
+ variables:
+ CMAKE_CONFIGURATION: fedora37_makefiles_clang
+ CMAKE_GENERATOR: "Unix Makefiles"
+
+.fedora37_ninja_clang:
+ extends: .fedora37
+
+ variables:
+ CMAKE_CONFIGURATION: fedora37_ninja_clang
+
### Sanitizers
.fedora_memcheck:
@@ -213,13 +226,13 @@
CTEST_MEMORYCHECK_TYPE: AddressSanitizer
CTEST_MEMORYCHECK_SANITIZER_OPTIONS: ""
-.fedora36_asan:
+.fedora37_asan:
extends:
- - .fedora36
+ - .fedora37
- .fedora_asan_addon
variables:
- CMAKE_CONFIGURATION: fedora36_asan
+ CMAKE_CONFIGURATION: fedora37_asan
### Intel Compiler
@@ -242,70 +255,86 @@
CMAKE_CONFIGURATION: inteloneapi_makefiles
CMAKE_GENERATOR: "Unix Makefiles"
-### CUDA builds
+### NVHPC Compiler
-.cuda9.2:
- image: "kitware/cmake:ci-cuda9.2-x86_64-2021-10-01"
+.nvhpc:
+ image: "kitware/cmake:ci-nvhpc22.11-x86_64-2022-12-06"
+ variables:
+ CMAKE_ARCH: x86_64
+.nvhpc_ninja:
+ extends: .nvhpc
+ variables:
+ CMAKE_CONFIGURATION: nvhpc_ninja
+
+### CUDA builds
+
+.cuda:
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
- CMAKE_ARCH: x86_64
CTEST_LABELS: "CUDA"
CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP: 1
+.cuda9.2:
+ extends: .cuda
+ image: "kitware/cmake:ci-cuda9.2-x86_64-2021-10-01"
+ variables:
+ CMAKE_ARCH: x86_64
+
.cuda9.2_nvidia:
extends: .cuda9.2
-
variables:
CMAKE_CONFIGURATION: cuda9.2_nvidia
CMAKE_GENERATOR: "Ninja Multi-Config"
.cuda10.2:
+ extends: .cuda
image: "kitware/cmake:ci-cuda10.2-x86_64-2021-06-16"
-
variables:
- GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
CMAKE_ARCH: x86_64
- CTEST_LABELS: "CUDA"
- CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP: 1
.cuda10.2_nvidia:
extends: .cuda10.2
-
variables:
CMAKE_CONFIGURATION: cuda10.2_nvidia
CTEST_NO_WARNINGS_ALLOWED: 1
.cuda10.2_clang:
extends: .cuda10.2
-
variables:
CMAKE_CONFIGURATION: cuda10.2_clang
CTEST_NO_WARNINGS_ALLOWED: 1
.cuda11.6:
+ extends: .cuda
image: "kitware/cmake:ci-cuda11.6-x86_64-2022-02-28"
-
variables:
- GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
CMAKE_ARCH: x86_64
- CTEST_LABELS: "CUDA"
- CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP: 1
.cuda11.6_nvidia:
extends: .cuda11.6
-
variables:
CMAKE_CONFIGURATION: cuda11.6_nvidia
CTEST_NO_WARNINGS_ALLOWED: 1
.cuda11.6_clang:
extends: .cuda11.6
-
variables:
CMAKE_CONFIGURATION: cuda11.6_clang
CTEST_NO_WARNINGS_ALLOWED: 1
+.cuda11.8_minimal:
+ extends: .cuda
+ image: "kitware/cmake:ci-cuda11.8-minimal-x86_64-2022-12-06"
+ variables:
+ CMAKE_ARCH: x86_64
+
+.cuda11.8_minimal_nvidia:
+ extends: .cuda11.8_minimal
+ variables:
+ CMAKE_CONFIGURATION: cuda11.8_minimal_nvidia
+ CTEST_NO_WARNINGS_ALLOWED: 1
+
### HIP builds
.hip4.2:
@@ -347,37 +376,66 @@
CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja_multi
CMAKE_GENERATOR: "Ninja Multi-Config"
+.clang_cxx_modules_x86_64:
+ image: "kitware/cmake:ci-clang_cxx_modules-x86_64-2023-02-15"
+
+ variables:
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ CMAKE_ARCH: x86_64
+ CC: "/opt/llvm-p1689/bin/clang"
+ CXX: "/opt/llvm-p1689/bin/clang++"
+
+.clang_cxx_modules_ninja:
+ extends: .clang_cxx_modules_x86_64
+
+ variables:
+ CMAKE_CONFIGURATION: linux_clang_cxx_modules_ninja
+
+.clang_cxx_modules_ninja_multi:
+ extends: .clang_cxx_modules_x86_64
+
+ variables:
+ CMAKE_CONFIGURATION: linux_clang_cxx_modules_ninja_multi
+ CMAKE_GENERATOR: "Ninja Multi-Config"
+
## Tags
-.linux_builder_tags:
+.linux_x86_64_tags:
tags:
- cmake
- build
- docker
- linux-x86_64
-.linux_builder_tags_x11:
+.linux_x86_64_tags_x11:
tags:
- cmake
- docker
- linux-x86_64
- x11
-.linux_builder_tags_cuda:
+.linux_x86_64_tags_cuda:
tags:
- cmake
- cuda-rt
- docker
- linux-x86_64
-.linux_builder_tags_radeon:
+.linux_x86_64_v3_tags_cuda:
+ tags:
+ - cmake
+ - cuda-rt
+ - docker
+ - linux-x86_64-v3
+
+.linux_x86_64_tags_radeon:
tags:
- cmake
- radeon
- docker
- linux-x86_64
-.linux_builder_tags_aarch64:
+.linux_aarch64_tags:
tags:
- cmake
- build
@@ -420,9 +478,9 @@
.cmake_codespell_linux:
stage: build
- extends: .fedora36
+ extends: .fedora37
script:
- - codespell
+ - .gitlab/ci/codespell.sh
interruptible: true
.cmake_build_linux:
@@ -433,8 +491,10 @@
- .gitlab/ci/sccache.sh
- sccache --start-server
- sccache --show-stats
+ - .gitlab/ci/pre_build.sh
- "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_configure.cmake"
- "$LAUNCHER ctest -VV -S .gitlab/ci/ctest_build.cmake"
+ - .gitlab/ci/post_build.sh
- sccache --show-stats
interruptible: true
@@ -542,7 +602,7 @@
extends:
- .intelclassic_makefiles
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
- .needs_centos6_x86_64
variables:
@@ -552,7 +612,7 @@
extends:
- .inteloneapi_makefiles
- .cmake_test_linux_release
- - .linux_builder_tags
+ - .linux_x86_64_tags
- .run_manually
- .needs_centos6_x86_64
variables:
@@ -563,8 +623,8 @@
.cmake_org_help:
stage: build
extends:
- - .fedora36
- - .linux_builder_tags
+ - .fedora37
+ - .linux_x86_64_tags
- .cmake_org_help_artifacts
script:
- *before_script_linux
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
index a79cc15..652a67a 100644
--- a/.gitlab/os-macos.yml
+++ b/.gitlab/os-macos.yml
@@ -90,7 +90,7 @@
## Tags
-.macos_x86_64_builder_tags:
+.macos_x86_64_tags:
tags:
- cmake # Since this is a bare runner, pin to a project.
- macos-x86_64
@@ -98,7 +98,7 @@
- xcode-14.2
- nonconcurrent
-.macos_x86_64_builder_tags_package:
+.macos_x86_64_tags_package:
tags:
- cmake # Since this is a bare runner, pin to a project.
- macos-x86_64
@@ -107,7 +107,7 @@
- nonconcurrent
- finder
-.macos_x86_64_builder_ext_tags:
+.macos_x86_64_tags_ext:
tags:
- cmake # Since this is a bare runner, pin to a project.
- macos-x86_64
@@ -115,7 +115,7 @@
- xcode-14.2
- concurrent
-.macos_arm64_builder_tags:
+.macos_arm64_tags:
tags:
- cmake # Since this is a bare runner, pin to a project.
- macos-arm64
@@ -123,7 +123,7 @@
- xcode-14.2
- nonconcurrent
-.macos_arm64_builder_ext_tags:
+.macos_arm64_tags_ext:
tags:
- cmake # Since this is a bare runner, pin to a project.
- macos-arm64
@@ -143,7 +143,7 @@
- ninja --version
# Download Qt
- cmake -P .gitlab/ci/download_qt.cmake
- - export CMAKE_PREFIX_PATH=$PWD/.gitlab/qt
+ - export CMAKE_PREFIX_PATH=$PWD/.gitlab/qt${CMAKE_PREFIX_PATH:+:$CMAKE_PREFIX_PATH}
.cmake_build_macos:
stage: build
@@ -154,25 +154,14 @@
# Allow the server to already be running.
- "sccache --start-server || :"
- sccache --show-stats
+ - .gitlab/ci/pre_build.sh
- ctest -VV -S .gitlab/ci/ctest_configure.cmake
- ctest -VV -S .gitlab/ci/ctest_build.cmake
+ - .gitlab/ci/post_build.sh
- 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
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index edd6136..ded3e65 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -35,19 +35,25 @@
variables:
VCVARSALL: "${VS170COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
VCVARSPLATFORM: "x64"
- VCVARSVERSION: "14.34.31933"
+ VCVARSVERSION: "14.35.32215"
.windows_vcvarsall_vs2022_x86:
variables:
VCVARSALL: "${VS170COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
VCVARSPLATFORM: "x86"
- VCVARSVERSION: "14.34.31933"
+ VCVARSVERSION: "14.35.32215"
.windows_vcvarsall_vs2022_x64_arm64:
variables:
VCVARSALL: "${VS170COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
VCVARSPLATFORM: "x64_arm64"
- VCVARSVERSION: "14.34.31933"
+ VCVARSVERSION: "14.35.32215"
+
+.windows_arm64_vcvarsall_vs2022:
+ variables:
+ VCVARSALL: "${VS170COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
+ VCVARSPLATFORM: "arm64"
+ VCVARSVERSION: "14.35.32215"
.windows_vs2022_x64_ninja:
extends:
@@ -57,6 +63,14 @@
variables:
CMAKE_CONFIGURATION: windows_vs2022_x64_ninja
+.windows_arm64_vs2022_ninja:
+ extends:
+ - .windows_build_ninja
+ - .windows_arm64_vcvarsall_vs2022
+
+ variables:
+ CMAKE_CONFIGURATION: windows_arm64_vs2022_ninja
+
.windows_package:
extends:
- .windows_build_ninja
@@ -98,7 +112,7 @@
CMAKE_CONFIGURATION: windows_vs2022_x64
CMAKE_GENERATOR: "Visual Studio 17 2022"
CMAKE_GENERATOR_PLATFORM: "x64"
- CMAKE_GENERATOR_TOOLSET: "v143,version=14.34.31933"
+ CMAKE_GENERATOR_TOOLSET: "v143,version=14.35.32215"
CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
.windows_vs2019_x64:
@@ -224,36 +238,69 @@
variables:
CMAKE_CONFIGURATION: windows_openwatcom1.9
+.windows_arm64_vs2022:
+ extends: .windows
+
+ variables:
+ CMAKE_CONFIGURATION: windows_arm64_vs2022
+ CMAKE_GENERATOR: "Visual Studio 17 2022"
+ CMAKE_GENERATOR_PLATFORM: "ARM64"
+ CMAKE_GENERATOR_TOOLSET: "v143,version=14.35.32215"
+ CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+.mingw_osdn_io:
+ extends: .windows
+
+ variables:
+ # Place MinGW environment in a path without spaces.
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake-ci-ext\\$CI_CONCURRENT_ID"
+ CMAKE_CI_BUILD_TYPE: Debug
+ CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+
+.mingw_osdn_io_mingw_makefiles:
+ extends: .mingw_osdn_io
+
+ variables:
+ CMAKE_CONFIGURATION: mingw_osdn_io_mingw_makefiles
+ CMAKE_GENERATOR: "MinGW Makefiles"
+
+.mingw_osdn_io_msys_makefiles:
+ extends: .mingw_osdn_io
+
+ variables:
+ CMAKE_CONFIGURATION: mingw_osdn_io_msys_makefiles
+ CMAKE_GENERATOR: "MSYS Makefiles"
+
## Tags
-.windows_tags_nonconcurrent_vs2022:
+.windows_x86_64_tags_nonconcurrent_vs2022:
tags:
- cmake # Since this is a bare runner, pin to a project.
- windows-x86_64
- shell
- vs2022
- - msvc-19.34
+ - msvc-19.35
- nonconcurrent
-.windows_tags_nonconcurrent_vs2022_arm64:
+.windows_x86_64_tags_nonconcurrent_vs2022_arm64:
tags:
- cmake # Since this is a bare runner, pin to a project.
- windows-x86_64
- shell
- vs2022
- - msvc-19.34-arm64
+ - msvc-19.35-arm64
- nonconcurrent
-.windows_tags_concurrent_vs2022:
+.windows_x86_64_tags_concurrent_vs2022:
tags:
- cmake # Since this is a bare runner, pin to a project.
- windows-x86_64
- shell
- vs2022
- - msvc-19.34
+ - msvc-19.35
- concurrent
-.windows_tags_concurrent_vs2019:
+.windows_x86_64_tags_concurrent_vs2019:
tags:
- cmake # Since this is a bare runner, pin to a project.
- windows-x86_64
@@ -262,13 +309,31 @@
- msvc-19.29-16.11
- concurrent
-.windows_tags_concurrent:
+.windows_x86_64_tags_concurrent:
tags:
- cmake # Since this is a bare runner, pin to a project.
- windows-x86_64
- shell
- concurrent
+.windows_arm64_tags_nonconcurrent_vs2022:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - windows-arm64
+ - shell
+ - vs2022
+ - msvc-19.35
+ - nonconcurrent
+
+.windows_arm64_tags_concurrent_vs2022:
+ tags:
+ - cmake # Since this is a bare runner, pin to a project.
+ - windows-arm64
+ - shell
+ - vs2022
+ - msvc-19.35
+ - concurrent
+
## Windows-specific scripts
.before_script_windows: &before_script_windows
@@ -281,11 +346,8 @@
- . .gitlab/ci/ninja-env.ps1
- (& "$env:WIX\bin\light.exe" -help) | Select -First 1
- cmake --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
+ - . .gitlab/ci/qt-env.ps1
+ - . .gitlab/ci/python-env.ps1
.cmake_build_windows:
stage: build
@@ -296,25 +358,15 @@
- Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
- sccache --start-server
- sccache --show-stats
+ - (& "$pwsh" -File ".gitlab/ci/pre_build.ps1")
- ctest -VV -S .gitlab/ci/ctest_configure.cmake
- ctest -VV -S .gitlab/ci/ctest_build.cmake
+ - (& "$pwsh" -File ".gitlab/ci/post_build.ps1")
- sccache --show-stats
- sccache --stop-server
interruptible: true
-.cmake_package_windows:
- stage: package
-
- script:
- - *before_script_windows
- - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
- - cd build
- - cpack -G ZIP
- - cpack -G WIX
-
- interruptible: true
-
.cmake_test_windows:
stage: test
diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml
index 8fc40a7f..b85b728 100644
--- a/.gitlab/rules.yml
+++ b/.gitlab/rules.yml
@@ -66,11 +66,15 @@
rules:
- if: '$CMAKE_CI_PACKAGE == "dev"'
variables:
- RSYNC_DESTINATION: "dev"
+ RSYNC_DESTINATION: "kitware@cmake.org:dev/"
when: on_success
- if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE == "prep"'
when: manual
- - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE != "package" && $CI_JOB_STAGE != "upload"'
+ - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE != "upload"'
+ when: on_success
+ - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE == "upload" && $CMAKE_CI_PACKAGE_URL != null'
+ variables:
+ RSYNC_DESTINATION: "$CMAKE_CI_PACKAGE_URL"
when: on_success
- when: never
@@ -78,19 +82,19 @@
rules:
- if: '$CMAKE_CI_PACKAGE =~ /v[0-9]+\.[0-9]+/'
variables:
- RSYNC_DESTINATION: "$CMAKE_CI_PACKAGE"
+ RSYNC_DESTINATION: "kitware@cmake.org:$CMAKE_CI_PACKAGE/"
CMAKE_CI_SPHINX_QTHELP: "ON"
CMAKE_CI_VERSION_NO_GIT: "ON"
when: manual
- if: '$CMAKE_CI_PROJECT_MAIN_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_MAIN_BRANCH == $CI_COMMIT_BRANCH'
variables:
- RSYNC_DESTINATION: "git-master"
+ RSYNC_DESTINATION: "kitware@cmake.org:git-master/"
CMAKE_CI_SPHINX_QTHELP: "OFF"
CMAKE_CI_VERSION_NO_GIT: "OFF"
when: on_success
- if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH'
variables:
- RSYNC_DESTINATION: "git-stage"
+ RSYNC_DESTINATION: "kitware@cmake.org:git-stage/"
CMAKE_CI_SPHINX_QTHELP: "OFF"
CMAKE_CI_VERSION_NO_GIT: "OFF"
when: on_success
diff --git a/.gitlab/upload.yml b/.gitlab/upload.yml
index f4a7c44..114808f 100644
--- a/.gitlab/upload.yml
+++ b/.gitlab/upload.yml
@@ -1,7 +1,7 @@
# Steps for uploading artifacts
.rsync_upload_package:
- image: "fedora:36"
+ image: "fedora:37"
stage: upload
tags:
- cmake
@@ -17,11 +17,11 @@
- chmod 400 $RSYNC_BINARY_KEY
- ssh-keygen -y -f $RSYNC_BINARY_KEY > $RSYNC_BINARY_KEY.pub
- test -n "$RSYNC_DESTINATION"
- - rsync -tv --recursive -e "ssh -i $RSYNC_BINARY_KEY -o StrictHostKeyChecking=no -o LogLevel=ERROR" build/ kitware@cmake.org:$RSYNC_DESTINATION/
+ - rsync -tv --recursive -e "ssh -i $RSYNC_BINARY_KEY -o StrictHostKeyChecking=no -o LogLevel=ERROR" build/ "$RSYNC_DESTINATION"
.rsync_upload_help:
stage: upload
- image: "fedora:36"
+ image: "fedora:37"
tags:
- cmake
- docker
@@ -36,4 +36,4 @@
- chmod 400 $RSYNC_HELP_KEY
- ssh-keygen -y -f $RSYNC_HELP_KEY > $RSYNC_HELP_KEY.pub
- test -n "$RSYNC_DESTINATION"
- - rsync -tv --recursive --delete -e "ssh -i $RSYNC_HELP_KEY -o StrictHostKeyChecking=no -o LogLevel=ERROR" build/html/ kitware@cmake.org:$RSYNC_DESTINATION/
+ - rsync -tv --recursive --delete -e "ssh -i $RSYNC_HELP_KEY -o StrictHostKeyChecking=no -o LogLevel=ERROR" build/html/ "$RSYNC_DESTINATION"
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 9eb993a..5e936c2 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -2013,6 +2013,7 @@ syn keyword cmakeKWExternalProject contained
\ IGNORED
\ INACTIVITY_TIMEOUT
\ INDEPENDENT_STEP_TARGETS
+ \ INSTALL_BYPRODUCTS
\ INSTALL_COMMAND
\ INSTALL_DIR
\ JOB_POOLS
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
index 38fec3f..798affd 100644
--- a/CMakeCPack.cmake
+++ b/CMakeCPack.cmake
@@ -264,5 +264,9 @@ set(CPACK_SOURCE_IGNORE_FILES
"~$"
)
+if(CMake_CPACK_CUSTOM_SCRIPT)
+ include(${CMake_CPACK_CUSTOM_SCRIPT})
+endif()
+
# include CPack model once all variables are set
include(CPack)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b9eb2d..0ce42fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,14 +1,10 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
-cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
-if(POLICY CMP0129)
- cmake_policy(SET CMP0129 NEW) # CMake 3.23
-endif()
-
project(CMake)
unset(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
unset(CMAKE_USER_MAKE_RULES_OVERRIDE_C)
@@ -73,11 +69,7 @@ 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()
+ include(${CMake_SOURCE_DIR}/Source/Checks/cm_cxx17_check.cmake)
if(NOT CMake_CXX17_BROKEN)
set(CMAKE_CXX_STANDARD 17)
else()
@@ -130,14 +122,12 @@ option(CMake_BUILD_DEVELOPER_REFERENCE
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()
+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()
@@ -251,10 +241,6 @@ macro(CMAKE_SETUP_TESTING)
configure_file(Tests/.NoDartCoverage Tests/.NoDartCoverage)
configure_file(Tests/.NoDartCoverage Modules/.NoDartCoverage)
configure_file(CTestCustom.cmake.in CTestCustom.cmake @ONLY)
- if(BUILD_TESTING AND DART_ROOT)
- configure_file(CMakeLogo.gif Testing/HTML/TestingResults/Icons/Logo.gif COPYONLY)
- endif()
- mark_as_advanced(DART_ROOT)
endmacro()
@@ -277,6 +263,25 @@ if(CMake_RUN_CLANG_TIDY)
endif()
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
+ option(CMake_USE_CLANG_TIDY_MODULE "Use CMake's clang-tidy module." OFF)
+ if(CMake_USE_CLANG_TIDY_MODULE)
+ find_library(CMake_CLANG_TIDY_MODULE NAMES cmake-clang-tidy-module DOC "Location of the clang-tidy module")
+ if(NOT CMake_CLANG_TIDY_MODULE)
+ message(FATAL_ERROR "CMake_USE_CLANG_TIDY_MODULE is ON but cmake-clang-tidy-module is not found!")
+ endif()
+ list(APPEND CMAKE_CXX_CLANG_TIDY "--load=${CMake_CLANG_TIDY_MODULE}")
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMake_CLANG_TIDY_MODULE}")
+ endif()
+
+ set(CMake_CLANG_TIDY_EXPORT_FIXES_DIR "" CACHE PATH "Directory to put clang-tidy fix files in.")
+ mark_as_advanced(CMake_CLANG_TIDY_EXPORT_FIXES_DIR)
+ if(CMake_CLANG_TIDY_EXPORT_FIXES_DIR)
+ if(NOT IS_ABSOLUTE "${CMake_CLANG_TIDY_EXPORT_FIXES_DIR}")
+ message(FATAL_ERROR "CMake_CLANG_TIDY_EXPORT_FIXES_DIR must be an absolute path!")
+ endif()
+ set(CMAKE_CXX_CLANG_TIDY_EXPORT_FIXES_DIR "${CMake_CLANG_TIDY_EXPORT_FIXES_DIR}")
+ endif()
+
# Create a preprocessor definition that depends on .clang-tidy content so
# the compile command will change when .clang-tidy changes. This ensures
# that a subsequent build re-runs clang-tidy on all sources even if they
@@ -286,6 +291,11 @@ if(CMake_RUN_CLANG_TIDY)
file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1)
set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
unset(clang_tidy_sha1)
+ if(CMake_USE_CLANG_TIDY_MODULE)
+ file(SHA1 "${CMake_CLANG_TIDY_MODULE}" clang_tidy_module_sha1)
+ list(APPEND CLANG_TIDY_DEFINITIONS "CLANG_TIDY_MODULE_SHA1=${clang_tidy_module_sha1}")
+ unset(clang_tidy_module_sha1)
+ endif()
endif()
configure_file(.clang-tidy .clang-tidy COPYONLY)
@@ -299,6 +309,11 @@ if(CMake_RUN_IWYU)
endif()
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
"${IWYU_COMMAND};-Xiwyu;--mapping_file=${CMake_SOURCE_DIR}/Utilities/IWYU/mapping.imp;-w")
+ option(CMake_IWYU_VERBOSE "Run include-what-you-use in verbose mode" OFF)
+ if (CMake_IWYU_VERBOSE)
+ list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ -Xiwyu -v7)
+ endif ()
list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${CMake_IWYU_OPTIONS})
endif()
@@ -342,9 +357,7 @@ endif()
#-----------------------------------------------------------------------
include(Source/CMakeVersion.cmake)
-# Include the standard Dart testing module
-enable_testing()
-include(${CMAKE_ROOT}/Modules/Dart.cmake)
+include(CTest)
# Set up test-time configuration.
set_directory_properties(PROPERTIES
diff --git a/CompileFlags.cmake b/CompileFlags.cmake
index bf8a082..6331af1 100644
--- a/CompileFlags.cmake
+++ b/CompileFlags.cmake
@@ -87,11 +87,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL SunPro AND
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")
diff --git a/Copyright.txt b/Copyright.txt
index bd45dd1..515e403 100644
--- a/Copyright.txt
+++ b/Copyright.txt
@@ -1,5 +1,5 @@
CMake - Cross Platform Makefile Generator
-Copyright 2000-2022 Kitware, Inc. and Contributors
+Copyright 2000-2023 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Help/command/DEVICE_LINK_OPTIONS.txt b/Help/command/DEVICE_LINK_OPTIONS.txt
index 3d50208..878754d 100644
--- a/Help/command/DEVICE_LINK_OPTIONS.txt
+++ b/Help/command/DEVICE_LINK_OPTIONS.txt
@@ -7,8 +7,6 @@ Host And Device Specific Link Options
: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.
+ :genex:`$<DEVICE_LINK:...>` generator expression will be used
+ only for the device link step. Options wrapped with :genex:`$<HOST_LINK:...>`
+ generator expression will be used only for the host link step.
diff --git a/Help/command/GENEX_NOTE.txt b/Help/command/GENEX_NOTE.txt
new file mode 100644
index 0000000..4a7906c
--- /dev/null
+++ b/Help/command/GENEX_NOTE.txt
@@ -0,0 +1,6 @@
+.. |more_see_also| replace:: See the :manual:`cmake-buildsystem(7)` manual
+ for more on defining buildsystem properties.
+
+Arguments to |command_name| may use generator expressions
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. |more_see_also|
diff --git a/Help/command/SUPPORTED_LANGUAGES.txt b/Help/command/SUPPORTED_LANGUAGES.txt
new file mode 100644
index 0000000..a98c07a
--- /dev/null
+++ b/Help/command/SUPPORTED_LANGUAGES.txt
@@ -0,0 +1,25 @@
+
+Supported languages are ``C``, ``CXX`` (i.e. C++), ``CSharp`` (i.e. C#), ``CUDA``,
+``OBJC`` (i.e. Objective-C), ``OBJCXX`` (i.e. Objective-C++), ``Fortran``, ``HIP``,
+``ISPC``, ``Swift``, ``ASM``, ``ASM_NASM``, ``ASM_MARMASM``, ``ASM_MASM``, and ``ASM-ATT``.
+
+ .. versionadded:: 3.8
+ Added ``CSharp`` and ``CUDA`` support.
+
+ .. versionadded:: 3.15
+ Added ``Swift`` support.
+
+ .. versionadded:: 3.16
+ Added ``OBJC`` and ``OBJCXX`` support.
+
+ .. versionadded:: 3.18
+ Added ``ISPC`` support.
+
+ .. versionadded:: 3.21
+ Added ``HIP`` support.
+
+ .. versionadded:: 3.26
+ Added ``ASM_MARMASM`` support.
+
+If enabling ``ASM``, list it last so that CMake can check whether
+compilers for other languages like ``C`` work for assembly too.
diff --git a/Help/command/add_compile_definitions.rst b/Help/command/add_compile_definitions.rst
index 48e33be..b2eb2af 100644
--- a/Help/command/add_compile_definitions.rst
+++ b/Help/command/add_compile_definitions.rst
@@ -21,7 +21,13 @@ 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.
+.. versionadded:: 3.26
+ Any leading ``-D`` on an item will be removed.
+
+.. |command_name| replace:: ``add_compile_definitions``
+.. include:: GENEX_NOTE.txt
+
+See Also
+^^^^^^^^
+
+* The command :command:`target_compile_definitions` adds target-specific definitions.
diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst
index 36f403c..0ccebc6 100644
--- a/Help/command/add_compile_options.rst
+++ b/Help/command/add_compile_options.rst
@@ -14,10 +14,8 @@ 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.
+.. |command_name| replace:: ``add_compile_options``
+.. include:: GENEX_NOTE.txt
.. include:: OPTIONS_SHELL.txt
@@ -30,22 +28,25 @@ 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)
+ # warning level 4
+ add_compile_options(/W4)
else()
- # lots of warnings and all warnings as errors
- add_compile_options(-Wall -Wextra -pedantic -Werror)
+ # additional warnings
+ add_compile_options(-Wall -Wextra -Wpedantic)
endif()
+To set per-language options, use the :genex:`$<COMPILE_LANGUAGE>`
+or :genex:`$<COMPILE_LANGUAGE:languages>` generator expressions.
+
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`.
+* 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 command :command:`target_compile_options` adds target-specific options.
-The source file property :prop_sf:`COMPILE_OPTIONS` adds options to one
-source file.
+* 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
index 99adc85..293d3f0 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -31,14 +31,12 @@ 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
+Do not list the output in more than one independent target that
+may build in parallel or the 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. See the
+`Example: Generating Files for Multiple Targets`_ below.
The options are:
@@ -140,6 +138,10 @@ The options are:
Display the given message before the commands are executed at
build time.
+ .. versionadded:: 3.26
+ Arguments to ``COMMENT`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
``DEPENDS``
Specify files on which the command depends. Each argument is converted
to a dependency as follows:
@@ -229,15 +231,24 @@ The options are:
``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.
+ If an output file name is a relative path, its absolute path is
+ determined by interpreting it relative to:
+
+ 1. the build directory corresponding to the current source directory
+ (:variable:`CMAKE_CURRENT_BINARY_DIR`), or
+
+ 2. the current source directory (:variable:`CMAKE_CURRENT_SOURCE_DIR`).
+
+ The path in the build directory is preferred unless the path in the
+ source tree is mentioned as an absolute source file path elsewhere
+ in the current directory.
+
.. versionadded:: 3.20
Arguments to ``OUTPUT`` may use a restricted set of
:manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -385,6 +396,49 @@ will re-run whenever ``in.txt`` changes.
where ``<config>`` is the build configuration, and then compile the generated
source as part of a library.
+Example: Generating Files for Multiple Targets
+""""""""""""""""""""""""""""""""""""""""""""""
+
+If multiple independent targets need the same custom command output,
+it must be attached to a single custom target on which they all depend.
+Consider the following example:
+
+.. code-block:: cmake
+
+ add_custom_command(
+ OUTPUT table.csv
+ COMMAND makeTable -i ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
+ -o table.csv
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
+ VERBATIM)
+ add_custom_target(generate_table_csv DEPENDS table.csv)
+
+ add_custom_command(
+ OUTPUT foo.cxx
+ COMMAND genFromTable -i table.csv -case foo -o foo.cxx
+ DEPENDS table.csv # file-level dependency
+ generate_table_csv # target-level dependency
+ VERBATIM)
+ add_library(foo foo.cxx)
+
+ add_custom_command(
+ OUTPUT bar.cxx
+ COMMAND genFromTable -i table.csv -case bar -o bar.cxx
+ DEPENDS table.csv # file-level dependency
+ generate_table_csv # target-level dependency
+ VERBATIM)
+ add_library(bar bar.cxx)
+
+Output ``foo.cxx`` is needed only by target ``foo`` and output ``bar.cxx``
+is needed only by target ``bar``, but *both* targets need ``table.csv``,
+transitively. Since ``foo`` and ``bar`` are independent targets that may
+build concurrently, we prevent them from racing to generate ``table.csv``
+by placing its custom command in a separate target, ``generate_table_csv``.
+The custom commands generating ``foo.cxx`` and ``bar.cxx`` each specify a
+target-level dependency on ``generate_table_csv``, so the targets using them,
+``foo`` and ``bar``, will not build until after target ``generate_table_csv``
+is built.
+
.. _`add_custom_command(TARGET)`:
Build Events
@@ -490,3 +544,8 @@ Ninja Multi-Config
``add_custom_command`` supports the :generator:`Ninja Multi-Config`
generator's cross-config capabilities. See the generator documentation
for more information.
+
+See Also
+^^^^^^^^
+
+* :command:`add_custom_target`
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index d8882ca..545b9a5 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -109,6 +109,10 @@ The options are:
Display the given message before the commands are executed at
build time.
+ .. versionadded:: 3.26
+ Arguments to ``COMMENT`` may use
+ :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
``DEPENDS``
Reference files and outputs of custom commands created with
:command:`add_custom_command` command calls in the same directory
@@ -181,3 +185,8 @@ Ninja Multi-Config
``add_custom_target`` supports the :generator:`Ninja Multi-Config`
generator's cross-config capabilities. See the generator documentation
for more information.
+
+See Also
+^^^^^^^^
+
+* :command:`add_custom_command`
diff --git a/Help/command/add_definitions.rst b/Help/command/add_definitions.rst
index fe69188..5c1f7b4 100644
--- a/Help/command/add_definitions.rst
+++ b/Help/command/add_definitions.rst
@@ -1,7 +1,7 @@
add_definitions
---------------
-Add -D define flags to the compilation of source files.
+Add ``-D`` define flags to the compilation of source files.
.. code-block:: cmake
@@ -31,5 +31,8 @@ backwards compatibility. See documentation of the
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.
+See Also
+^^^^^^^^
+
+* 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
index 14c0183..23cb405 100644
--- a/Help/command/add_dependencies.rst
+++ b/Help/command/add_dependencies.rst
@@ -20,7 +20,12 @@ 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.
+See Also
+^^^^^^^^
+
+* The ``DEPENDS`` option of :command:`add_custom_target` and
+ :command:`add_custom_command` commands for adding file-level
+ dependencies in custom rules.
+
+* 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
index dde9429..d9ea0da 100644
--- a/Help/command/add_executable.rst
+++ b/Help/command/add_executable.rst
@@ -107,3 +107,8 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`add_library`
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index 7dc4365..07c8bab 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -83,10 +83,10 @@ Object Libraries
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
+library. Instead other targets created by ``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:
+form :genex:`$\<TARGET_OBJECTS:objlib\> <TARGET_OBJECTS>` as a source, where
+``objlib`` is the object library name. For example:
.. code-block:: cmake
@@ -101,7 +101,7 @@ 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>``.
+:genex:`$\<TARGET_OBJECTS:objlib\> <TARGET_OBJECTS>`.
.. versionadded:: 3.12
Object libraries can be linked to with :command:`target_link_libraries`.
@@ -261,3 +261,8 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`add_executable`
diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst
index f03e7c0..c09e106 100644
--- a/Help/command/add_link_options.rst
+++ b/Help/command/add_link_options.rst
@@ -23,13 +23,18 @@ exist to add libraries (:command:`target_link_libraries` or
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.
+.. |command_name| replace:: ``add_link_options``
+.. include:: GENEX_NOTE.txt
.. include:: DEVICE_LINK_OPTIONS.txt
.. include:: OPTIONS_SHELL.txt
.. include:: LINK_OPTIONS_LINKER.txt
+
+See Also
+^^^^^^^^
+
+* :command:`link_libraries`
+* :command:`target_link_libraries`
+* :command:`target_link_options`
diff --git a/Help/command/block.rst b/Help/command/block.rst
index dfd60d4..a352e83 100644
--- a/Help/command/block.rst
+++ b/Help/command/block.rst
@@ -71,6 +71,6 @@ inside the block.
See Also
^^^^^^^^
- * :command:`endblock`
- * :command:`return`
- * :command:`cmake_policy`
+* :command:`endblock`
+* :command:`return`
+* :command:`cmake_policy`
diff --git a/Help/command/build_name.rst b/Help/command/build_name.rst
index 2a1fbae..5acf858 100644
--- a/Help/command/build_name.rst
+++ b/Help/command/build_name.rst
@@ -5,7 +5,7 @@ Disallowed since version 3.0. See CMake Policy :policy:`CMP0036`.
Use ``${CMAKE_SYSTEM}`` and ``${CMAKE_CXX_COMPILER}`` instead.
-::
+.. code-block:: cmake
build_name(variable)
diff --git a/Help/command/cmake_host_system_information.rst b/Help/command/cmake_host_system_information.rst
index c84c5b5..76824ef 100644
--- a/Help/command/cmake_host_system_information.rst
+++ b/Help/command/cmake_host_system_information.rst
@@ -17,7 +17,7 @@ Synopsis
Query host system specific information
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-::
+.. code-block:: cmake
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
diff --git a/Help/command/cmake_minimum_required.rst b/Help/command/cmake_minimum_required.rst
index d159770..031bd56 100644
--- a/Help/command/cmake_minimum_required.rst
+++ b/Help/command/cmake_minimum_required.rst
@@ -79,3 +79,8 @@ invokes
cmake_policy(VERSION 2.4[...<max>])
which enables compatibility features for CMake 2.4 and lower.
+
+See Also
+^^^^^^^^
+
+* :command:`cmake_policy`
diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst
index 7c85da6..0bb1d91 100644
--- a/Help/command/cmake_parse_arguments.rst
+++ b/Help/command/cmake_parse_arguments.rst
@@ -113,3 +113,9 @@ interpreted as the beginning of the new option. E.g.
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``.
+
+See Also
+^^^^^^^^
+
+* :command:`function`
+* :command:`macro`
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
index eb7da07..4e6bedb 100644
--- a/Help/command/cmake_path.rst
+++ b/Help/command/cmake_path.rst
@@ -237,7 +237,7 @@ 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.
-::
+.. code-block:: cmake
cmake_path(GET <path-var> ROOT_NAME <out-var>)
cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
@@ -408,7 +408,7 @@ meaning of each path component.
.. _HAS_RELATIVE_PART:
.. _HAS_PARENT_PATH:
-::
+.. code-block:: cmake
cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
@@ -432,7 +432,7 @@ Note the following special cases:
.. _IS_ABSOLUTE:
-::
+.. code-block:: cmake
cmake_path(IS_ABSOLUTE <path-var> <out-var>)
@@ -446,7 +446,7 @@ false while ``HAS_ROOT_DIRECTORY`` can be true.
.. _IS_RELATIVE:
-::
+.. code-block:: cmake
cmake_path(IS_RELATIVE <path-var> <out-var>)
@@ -454,7 +454,7 @@ This will store the opposite of ``IS_ABSOLUTE`` in ``<out-var>``.
.. _IS_PREFIX:
-::
+.. code-block:: cmake
cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
@@ -476,7 +476,7 @@ are :ref:`normalized <Normalization>` before the check.
.. _Path COMPARE:
.. _COMPARE:
-::
+.. code-block:: cmake
cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
@@ -510,7 +510,7 @@ Modification
.. _cmake_path-SET:
-::
+.. code-block:: cmake
cmake_path(SET <path-var> [NORMALIZE] <input>)
@@ -539,7 +539,7 @@ Output::
.. _APPEND:
-::
+.. code-block:: cmake
cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
@@ -570,7 +570,7 @@ the following algorithm (pseudo-code) applies:
.. _APPEND_STRING:
-::
+.. code-block:: cmake
cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
@@ -579,7 +579,7 @@ Append all the ``<input>`` arguments to the ``<path-var>`` without adding any
.. _REMOVE_FILENAME:
-::
+.. code-block:: cmake
cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
@@ -609,7 +609,7 @@ Output::
.. _REPLACE_FILENAME:
-::
+.. code-block:: cmake
cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
@@ -628,7 +628,7 @@ equivalent to the following:
.. _REMOVE_EXTENSION:
-::
+.. code-block:: cmake
cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
[OUTPUT_VARIABLE <out-var>])
@@ -637,7 +637,7 @@ Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
.. _REPLACE_EXTENSION:
-::
+.. code-block:: cmake
cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
[OUTPUT_VARIABLE <out-var>])
@@ -661,7 +661,7 @@ Generation
.. _NORMAL_PATH:
-::
+.. code-block:: cmake
cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
@@ -670,7 +670,7 @@ Normalize ``<path-var>`` according the steps described in :ref:`Normalization`.
.. _cmake_path-RELATIVE_PATH:
.. _RELATIVE_PATH:
-::
+.. code-block:: cmake
cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
[OUTPUT_VARIABLE <out-var>])
@@ -686,7 +686,7 @@ as that used by C++
.. _ABSOLUTE_PATH:
-::
+.. code-block:: cmake
cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
[OUTPUT_VARIABLE <out-var>])
@@ -713,7 +713,7 @@ target platform when cross-compiling.
.. _cmake_path-NATIVE_PATH:
.. _NATIVE_PATH:
-::
+.. code-block:: cmake
cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
@@ -727,7 +727,7 @@ When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
.. _cmake_path-TO_CMAKE_PATH_LIST:
.. _TO_CMAKE_PATH_LIST:
-::
+.. code-block:: cmake
cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
@@ -749,7 +749,7 @@ When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
.. _cmake_path-TO_NATIVE_PATH_LIST:
.. _TO_NATIVE_PATH_LIST:
-::
+.. code-block:: cmake
cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
@@ -788,7 +788,7 @@ Hashing
.. _HASH:
-::
+.. code-block:: cmake
cmake_path(HASH <path-var> <out-var>)
diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst
index 54fc548..cde74a7 100644
--- a/Help/command/cmake_policy.rst
+++ b/Help/command/cmake_policy.rst
@@ -150,3 +150,8 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`cmake_minimum_required`
diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst
index 1d81423..6f4cedf 100644
--- a/Help/command/configure_file.rst
+++ b/Help/command/configure_file.rst
@@ -58,7 +58,7 @@ or
#define VAR 1
Input lines of the form ``#cmakedefine01 VAR ...`` will expand
-as ``#cmakedefine01 VAR ... 0`` or ``#cmakedefine01 VAR ... 0``,
+as ``#cmakedefine01 VAR ... 0`` or ``#cmakedefine01 VAR ... 1``,
which may lead to undefined behavior.
.. versionadded:: 3.10
@@ -174,11 +174,16 @@ Otherwise it will contain:
/* #undef FOO_ENABLE */
/* #undef FOO_STRING */
-One may then use the :command:`include_directories` command to
+One may then use the :command:`target_include_directories` command to
specify the output directory as an include directory:
.. code-block:: cmake
- include_directories(${CMAKE_CURRENT_BINARY_DIR})
+ target_include_directories(<target> [SYSTEM] <INTERFACE|PUBLIC|PRIVATE> "${CMAKE_CURRENT_BINARY_DIR}")
so that sources may include the header as ``#include <foo.h>``.
+
+See Also
+^^^^^^^^
+
+* :command:`file(GENERATE)`
diff --git a/Help/command/ctest_build.rst b/Help/command/ctest_build.rst
index 8c81f2d..bce1739 100644
--- a/Help/command/ctest_build.rst
+++ b/Help/command/ctest_build.rst
@@ -3,7 +3,7 @@ ctest_build
Perform the :ref:`CTest Build Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_build([BUILD <build-dir>] [APPEND]
[CONFIGURATION <config>]
diff --git a/Help/command/ctest_configure.rst b/Help/command/ctest_configure.rst
index 95712aa..f23dd22 100644
--- a/Help/command/ctest_configure.rst
+++ b/Help/command/ctest_configure.rst
@@ -3,7 +3,7 @@ ctest_configure
Perform the :ref:`CTest Configure Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_configure([BUILD <build-dir>] [SOURCE <source-dir>] [APPEND]
[OPTIONS <options>] [RETURN_VALUE <result-var>] [QUIET]
diff --git a/Help/command/ctest_coverage.rst b/Help/command/ctest_coverage.rst
index a6c643b..319c978 100644
--- a/Help/command/ctest_coverage.rst
+++ b/Help/command/ctest_coverage.rst
@@ -3,7 +3,7 @@ ctest_coverage
Perform the :ref:`CTest Coverage Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_coverage([BUILD <build-dir>] [APPEND]
[LABELS <label>...]
diff --git a/Help/command/ctest_empty_binary_directory.rst b/Help/command/ctest_empty_binary_directory.rst
index 7753667..5d26de1 100644
--- a/Help/command/ctest_empty_binary_directory.rst
+++ b/Help/command/ctest_empty_binary_directory.rst
@@ -3,9 +3,9 @@ ctest_empty_binary_directory
empties the binary directory
-::
+.. code-block:: cmake
- ctest_empty_binary_directory( 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
diff --git a/Help/command/ctest_memcheck.rst b/Help/command/ctest_memcheck.rst
index 8b79077..4ca7364 100644
--- a/Help/command/ctest_memcheck.rst
+++ b/Help/command/ctest_memcheck.rst
@@ -3,7 +3,7 @@ ctest_memcheck
Perform the :ref:`CTest MemCheck Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_memcheck([BUILD <build-dir>] [APPEND]
[START <start-number>]
diff --git a/Help/command/ctest_read_custom_files.rst b/Help/command/ctest_read_custom_files.rst
index cf8e17a..53c093e 100644
--- a/Help/command/ctest_read_custom_files.rst
+++ b/Help/command/ctest_read_custom_files.rst
@@ -3,9 +3,9 @@ ctest_read_custom_files
read CTestCustom files.
-::
+.. code-block:: cmake
- ctest_read_custom_files( directory ... )
+ ctest_read_custom_files(<directory>...)
Read all the CTestCustom.ctest or CTestCustom.cmake files from the
given directory.
diff --git a/Help/command/ctest_run_script.rst b/Help/command/ctest_run_script.rst
index a2b348f..145bd90 100644
--- a/Help/command/ctest_run_script.rst
+++ b/Help/command/ctest_run_script.rst
@@ -3,7 +3,7 @@ ctest_run_script
runs a :option:`ctest -S` script
-::
+.. code-block:: cmake
ctest_run_script([NEW_PROCESS] script_file_name script_file_name1
script_file_name2 ... [RETURN_VALUE var])
diff --git a/Help/command/ctest_sleep.rst b/Help/command/ctest_sleep.rst
index 16a914c..42b9768 100644
--- a/Help/command/ctest_sleep.rst
+++ b/Help/command/ctest_sleep.rst
@@ -3,13 +3,13 @@ ctest_sleep
sleeps for some amount of time
-::
+.. code-block:: cmake
ctest_sleep(<seconds>)
Sleep for given number of seconds.
-::
+.. code-block:: cmake
ctest_sleep(<time1> <duration> <time2>)
diff --git a/Help/command/ctest_start.rst b/Help/command/ctest_start.rst
index 921279a..2d68a37 100644
--- a/Help/command/ctest_start.rst
+++ b/Help/command/ctest_start.rst
@@ -3,7 +3,7 @@ ctest_start
Starts the testing for a given model
-::
+.. code-block:: cmake
ctest_start(<model> [<source> [<binary>]] [GROUP <group>] [QUIET])
diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst
index d661825..3b6bf3a 100644
--- a/Help/command/ctest_submit.rst
+++ b/Help/command/ctest_submit.rst
@@ -3,7 +3,7 @@ ctest_submit
Perform the :ref:`CTest Submit Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_submit([PARTS <part>...] [FILES <file>...]
[SUBMIT_URL <url>]
@@ -96,7 +96,7 @@ Submit to CDash Upload API
.. versionadded:: 3.2
-::
+.. code-block:: cmake
ctest_submit(CDASH_UPLOAD <file> [CDASH_UPLOAD_TYPE <type>]
[SUBMIT_URL <url>]
diff --git a/Help/command/ctest_test.rst b/Help/command/ctest_test.rst
index 4f9f891..cf20ade 100644
--- a/Help/command/ctest_test.rst
+++ b/Help/command/ctest_test.rst
@@ -3,7 +3,7 @@ ctest_test
Perform the :ref:`CTest Test Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_test([BUILD <build-dir>] [APPEND]
[START <start-number>]
@@ -30,7 +30,7 @@ Perform the :ref:`CTest Test Step` as a :ref:`Dashboard Client`.
)
..
- _note: If updating the argument list here, please also update the argument
+ NOTE If updating the argument list here, please also update the argument
list documentation for :command:`ctest_memcheck` as well.
Run tests in the project build tree and store results in
diff --git a/Help/command/ctest_update.rst b/Help/command/ctest_update.rst
index 63f991b..836cdf1 100644
--- a/Help/command/ctest_update.rst
+++ b/Help/command/ctest_update.rst
@@ -3,7 +3,7 @@ ctest_update
Perform the :ref:`CTest Update Step` as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_update([SOURCE <source-dir>]
[RETURN_VALUE <result-var>]
diff --git a/Help/command/ctest_upload.rst b/Help/command/ctest_upload.rst
index ffddd0a..344979a 100644
--- a/Help/command/ctest_upload.rst
+++ b/Help/command/ctest_upload.rst
@@ -3,7 +3,7 @@ ctest_upload
Upload files to a dashboard server as a :ref:`Dashboard Client`.
-::
+.. code-block:: cmake
ctest_upload(FILES <file>... [QUIET] [CAPTURE_CMAKE_ERROR <result-var>])
diff --git a/Help/command/define_property.rst b/Help/command/define_property.rst
index 76b060b..5278e30 100644
--- a/Help/command/define_property.rst
+++ b/Help/command/define_property.rst
@@ -73,3 +73,9 @@ project via corresponding options to the :command:`get_property` command.
with ``CMAKE_`` or ``_CMAKE_``. The property name must contain at least one
underscore. It is recommended that the property name have a prefix specific
to the project.
+
+See Also
+^^^^^^^^
+
+* :command:`get_property`
+* :command:`set_property`
diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst
index d9103b8..21b38ba 100644
--- a/Help/command/enable_language.rst
+++ b/Help/command/enable_language.rst
@@ -9,24 +9,13 @@ Enable languages (CXX/C/OBJC/OBJCXX/Fortran/etc)
Enables support for the named languages 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``,
-``HIP``, ``ISPC``, and ``ASM``.
+variables that are created by the project command.
-.. versionadded:: 3.8
- Added ``CUDA`` support.
+.. include:: SUPPORTED_LANGUAGES.txt
-.. versionadded:: 3.16
- Added ``OBJC`` and ``OBJCXX`` support.
-
-.. versionadded:: 3.18
- Added ``ISPC`` support.
-
-.. versionadded:: 3.21
- Added ``HIP`` support.
-
-If enabling ``ASM``, enable it last so that CMake can check whether
-compilers for other languages like ``C`` work for assembly too.
+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.
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
diff --git a/Help/command/exec_program.rst b/Help/command/exec_program.rst
index bc9b069..983a6df 100644
--- a/Help/command/exec_program.rst
+++ b/Help/command/exec_program.rst
@@ -8,7 +8,7 @@ exec_program
Run an executable program during the processing of the CMakeList.txt
file.
-::
+.. code-block:: cmake
exec_program(Executable [directory in which to run]
[ARGS <arguments to executable>]
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
index d4ba465..98430c5 100644
--- a/Help/command/execute_process.rst
+++ b/Help/command/execute_process.rst
@@ -32,6 +32,11 @@ 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.
+``execute_process`` runs commands while CMake is configuring the project,
+prior to build system generation. Use the :command:`add_custom_target` and
+:command:`add_custom_command` commands to create custom commands that run
+at build time.
+
Options:
``COMMAND``
@@ -51,8 +56,8 @@ Options:
(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.
+ For **sequential execution** of multiple commands use multiple
+ ``execute_process`` calls each with a single ``COMMAND`` argument.
``WORKING_DIRECTORY``
The named directory will be set as the current working directory of
@@ -76,22 +81,46 @@ Options:
given ``COMMAND`` arguments. Each entry will be an integer return code
from the corresponding child or a string describing an error condition.
+``INPUT_FILE <file>``
+ ``<file>`` is attached to the standard input pipe of the *first* ``COMMAND``
+ process.
+
+``OUTPUT_FILE <file>``
+ ``<file>`` is attached to the standard output pipe of the *last* ``COMMAND``
+ process.
+
+``ERROR_FILE <file>``
+ ``<file>`` is attached to the standard error pipe of *all* ``COMMAND``
+ processes.
+
+.. versionadded:: 3.3
+ If the same ``<file>`` is named for both ``OUTPUT_FILE`` and ``ERROR_FILE``
+ then it will be used for both standard output and standard error pipes.
+
+``OUTPUT_QUIET``, ``ERROR_QUIET``
+ The standard output on ``OUTPUT_VARIABLE`` or standard error on
+ ``ERROR_VARIABLE`` are not connected (no variable content).
+ The ``*_FILE`` and ``ECHO_*_VARIABLE`` options are not affected.
+
``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.
+``ECHO_OUTPUT_VARIABLE``, ``ECHO_ERROR_VARIABLE``
+ .. versionadded:: 3.18
+
+ The standard output or standard error will not be exclusively redirected to
+ the specified variables.
- .. versionadded:: 3.3
- If the same file is named for both output and error then it will be used
- for both.
+ The output will be duplicated into the specified variables and also onto
+ standard output or standard error analogous to the ``tee`` Unix command.
-``OUTPUT_QUIET``, ``ERROR_QUIET``
- The standard output or standard error results will be quietly ignored.
+.. note::
+ 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.
``COMMAND_ECHO <where>``
.. versionadded:: 3.15
@@ -126,17 +155,6 @@ Options:
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
@@ -151,15 +169,3 @@ Options:
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_library_dependencies.rst b/Help/command/export_library_dependencies.rst
index 9753abf..6cb4643 100644
--- a/Help/command/export_library_dependencies.rst
+++ b/Help/command/export_library_dependencies.rst
@@ -15,7 +15,7 @@ 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.
-::
+.. code-block:: cmake
export_library_dependencies(<file> [APPEND])
diff --git a/Help/command/file.rst b/Help/command/file.rst
index fbe2a81..df895d0 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -526,10 +526,10 @@ from the input content to produce the output content. The options are:
``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.
+ such as :genex:`$<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
@@ -540,8 +540,9 @@ from the input content to produce the output content. The options are:
.. 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>``).
+ require a target for evaluation (e.g.
+ :genex:`$<COMPILE_FEATURES:...>`,
+ :genex:`$<TARGET_PROPERTY:prop>`).
``NO_SOURCE_PERMISSIONS``
.. versionadded:: 3.20
@@ -749,7 +750,8 @@ The options are:
file(COPY_FILE <oldname> <newname>
[RESULT <result>]
- [ONLY_IF_DIFFERENT])
+ [ONLY_IF_DIFFERENT]
+ [INPUT_MAY_BE_RECENT])
.. versionadded:: 3.21
@@ -768,6 +770,14 @@ The options are:
contents are already the same as ``<oldname>`` (this avoids updating
``<newname>``'s timestamp).
+``INPUT_MAY_BE_RECENT``
+ .. versionadded:: 3.26
+
+ Tell CMake that the input file may have been recently created. This is
+ meaningful only on Windows, where files may be inaccessible for a short
+ time after they are created. With this option, if permission is denied,
+ CMake will retry reading the input a few times.
+
This sub-command has some similarities to :command:`configure_file` with the
``COPYONLY`` option. An important difference is that :command:`configure_file`
creates a dependency on the source file, so CMake will be re-run if it changes.
@@ -1213,6 +1223,9 @@ directed to do so with the ``COMPRESSION`` option. Valid values for
The ``<compression-level>`` should be between 0-9, with the default being 0.
The ``COMPRESSION`` option must be present when ``COMPRESSION_LEVEL`` is given.
+.. versionadded:: 3.26
+ The ``<compression-level>`` of the ``Zstd`` algorithm can be set between 0-19.
+
.. note::
With ``FORMAT`` set to ``raw`` only one file will be compressed with the
compression type specified by ``COMPRESSION``.
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index c99c73d..de4cb88 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -370,7 +370,8 @@ 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.
+ where ``<PackageName>`` is the package to be found
+ (the case-preserved first argument to ``find_package``).
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.
diff --git a/Help/command/foreach.rst b/Help/command/foreach.rst
index ddf8dfa..c3fdbf7 100644
--- a/Help/command/foreach.rst
+++ b/Help/command/foreach.rst
@@ -74,8 +74,7 @@ processed:
message(STATUS "X=${X}")
endforeach()
-yields
-::
+yields::
-- X=0
-- X=1
@@ -119,8 +118,7 @@ iteration variables as follows:
message(STATUS "en=${en}, ba=${ba}")
endforeach()
-yields
-::
+yields::
-- num_0=one, num_1=satu
-- num_0=two, num_1=dua
diff --git a/Help/command/function.rst b/Help/command/function.rst
index fc55c03..069f9fa 100644
--- a/Help/command/function.rst
+++ b/Help/command/function.rst
@@ -77,5 +77,6 @@ extra argument.
See Also
^^^^^^^^
+* :command:`cmake_parse_arguments`
* :command:`endfunction`
* :command:`return`
diff --git a/Help/command/get_cmake_property.rst b/Help/command/get_cmake_property.rst
index 96764a3..b1d18a0 100644
--- a/Help/command/get_cmake_property.rst
+++ b/Help/command/get_cmake_property.rst
@@ -12,9 +12,12 @@ 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.
+
+See Also
+^^^^^^^^
+
+* the :command:`get_property` command ``GLOBAL`` option
diff --git a/Help/command/get_directory_property.rst b/Help/command/get_directory_property.rst
index 0ccbfb0..209d2f8 100644
--- a/Help/command/get_directory_property.rst
+++ b/Help/command/get_directory_property.rst
@@ -33,4 +33,9 @@ the search will chain to a parent scope as described for the
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.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* the more general :command:`get_property` command
diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst
index 4bfe087..899ede6 100644
--- a/Help/command/get_filename_component.rst
+++ b/Help/command/get_filename_component.rst
@@ -69,3 +69,8 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`cmake_path`
diff --git a/Help/command/get_property.rst b/Help/command/get_property.rst
index 46da285..6b9931e 100644
--- a/Help/command/get_property.rst
+++ b/Help/command/get_property.rst
@@ -99,3 +99,9 @@ documentation is requested for a property that has not been defined
The :prop_sf:`GENERATED` source file property may be globally visible.
See its documentation for details.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* :command:`set_property`
diff --git a/Help/command/get_source_file_property.rst b/Help/command/get_source_file_property.rst
index ae41565..e83e9c2 100644
--- a/Help/command/get_source_file_property.rst
+++ b/Help/command/get_source_file_property.rst
@@ -39,9 +39,14 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* the more general :command:`get_property` command
+* :command:`set_source_files_properties`
diff --git a/Help/command/get_target_property.rst b/Help/command/get_target_property.rst
index 985b1ff..8c6dcb1 100644
--- a/Help/command/get_target_property.rst
+++ b/Help/command/get_target_property.rst
@@ -22,6 +22,10 @@ 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 Also
+^^^^^^^^
-See :ref:`Target Properties` for the list of properties known to CMake.
+* :command:`define_property`
+* the more general :command:`get_property` command
+* :command:`set_target_properties`
+* :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
index 6bcc1ef..2b6f354 100644
--- a/Help/command/get_test_property.rst
+++ b/Help/command/get_test_property.rst
@@ -19,4 +19,8 @@ an empty string.
For a list of standard properties you can type
:option:`cmake --help-property-list`.
-See also the more general :command:`get_property` command.
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* the more general :command:`get_property` command
diff --git a/Help/command/if.rst b/Help/command/if.rst
index b72769f..684c113 100644
--- a/Help/command/if.rst
+++ b/Help/command/if.rst
@@ -165,6 +165,8 @@ File Operations
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.
+ False if the given path is an empty string.
+
``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
@@ -173,10 +175,12 @@ File Operations
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
+``if(IS_DIRECTORY path)``
+ True if ``path`` is a directory. Behavior is well-defined only
for full paths.
+ False if the given path is an empty string.
+
``if(IS_SYMLINK file-name)``
True if the given name is a symbolic link. Behavior is well-defined
only for full paths.
@@ -428,6 +432,6 @@ condition syntax accepts ``<variable|string>``.
See also
^^^^^^^^
- * :command:`else`
- * :command:`elseif`
- * :command:`endif`
+* :command:`else`
+* :command:`elseif`
+* :command:`endif`
diff --git a/Help/command/include_directories.rst b/Help/command/include_directories.rst
index fe281c3..d2948ed 100644
--- a/Help/command/include_directories.rst
+++ b/Help/command/include_directories.rst
@@ -29,13 +29,16 @@ 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.
+.. |command_name| replace:: ``include_directories``
+.. include:: GENEX_NOTE.txt
.. note::
Prefer the :command:`target_include_directories` command to add include
directories to individual targets and optionally propagate/export them
to dependents.
+
+See Also
+^^^^^^^^
+
+* :command:`target_include_directories`
diff --git a/Help/command/include_guard.rst b/Help/command/include_guard.rst
index dca3b6f..e8cafac 100644
--- a/Help/command/include_guard.rst
+++ b/Help/command/include_guard.rst
@@ -13,7 +13,7 @@ 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
+``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
diff --git a/Help/command/install.rst b/Help/command/install.rst
index feff436..126888a 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -32,7 +32,7 @@ are executed in order during installation.
.. versionchanged:: 3.22
The environment variable :envvar:`CMAKE_INSTALL_MODE` can override the
- default copying behavior of :command:`install()`.
+ default copying behavior of ``install()``.
There are multiple signatures for this command. Some of them define
installation options for files and targets. Options common to
@@ -379,7 +379,7 @@ top level:
: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>``.
+ :genex:`$<INSTALL_PREFIX>`.
``RUNTIME_DEPENDENCY_SET``
.. versionadded:: 3.21
diff --git a/Help/command/install_files.rst b/Help/command/install_files.rst
index 494f3d0..9b19124 100644
--- a/Help/command/install_files.rst
+++ b/Help/command/install_files.rst
@@ -11,7 +11,7 @@ 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.
-::
+.. code-block:: cmake
install_files(<dir> extension file file ...)
@@ -23,14 +23,14 @@ 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``.
-::
+.. code-block:: cmake
install_files(<dir> regexp)
Any files in the current source directory that match the regular
expression will be installed.
-::
+.. code-block:: cmake
install_files(<dir> FILES file file ...)
diff --git a/Help/command/install_programs.rst b/Help/command/install_programs.rst
index eafae89..5b42904 100644
--- a/Help/command/install_programs.rst
+++ b/Help/command/install_programs.rst
@@ -11,7 +11,7 @@ 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.
-::
+.. code-block:: cmake
install_programs(<dir> file1 file2 [file3 ...])
install_programs(<dir> FILES file1 [file2 ...])
@@ -20,7 +20,7 @@ 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.
-::
+.. code-block:: cmake
install_programs(<dir> regexp)
diff --git a/Help/command/install_targets.rst b/Help/command/install_targets.rst
index 9355f8d..7653776 100644
--- a/Help/command/install_targets.rst
+++ b/Help/command/install_targets.rst
@@ -8,7 +8,7 @@ install_targets
This command has been superseded by the :command:`install` command. It is
provided for compatibility with older CMake code.
-::
+.. code-block:: cmake
install_targets(<dir> [RUNTIME_DIRECTORY dir] target target)
diff --git a/Help/command/link_directories.rst b/Help/command/link_directories.rst
index 6732402..5e7fc39 100644
--- a/Help/command/link_directories.rst
+++ b/Help/command/link_directories.rst
@@ -53,3 +53,9 @@ The command will apply only to targets created after it is called.
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.
+
+See Also
+^^^^^^^^
+
+* :command:`target_link_directories`
+* :command:`target_link_libraries`
diff --git a/Help/command/load_command.rst b/Help/command/load_command.rst
index dc23599..4b3888f 100644
--- a/Help/command/load_command.rst
+++ b/Help/command/load_command.rst
@@ -5,7 +5,7 @@ Disallowed since version 3.0. See CMake Policy :policy:`CMP0031`.
Load a command into a running CMake.
-::
+.. code-block:: cmake
load_command(COMMAND_NAME <loc1> [loc2 ...])
@@ -15,7 +15,7 @@ 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
-::
+.. code-block:: cmake
CMAKE_LOADED_COMMAND_<COMMAND_NAME>
diff --git a/Help/command/macro.rst b/Help/command/macro.rst
index 5fe4c00..2858622 100644
--- a/Help/command/macro.rst
+++ b/Help/command/macro.rst
@@ -149,3 +149,9 @@ existing variable instead of the arguments. For example:
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.
+
+See Also
+^^^^^^^^
+
+* :command:`cmake_parse_arguments`
+* :command:`endmacro`
diff --git a/Help/command/make_directory.rst b/Help/command/make_directory.rst
index 8469b0a..959749d 100644
--- a/Help/command/make_directory.rst
+++ b/Help/command/make_directory.rst
@@ -5,7 +5,7 @@ make_directory
Use the :command:`file(MAKE_DIRECTORY)` command instead.
-::
+.. code-block:: cmake
make_directory(directory)
diff --git a/Help/command/message.rst b/Help/command/message.rst
index 77d21c8..e8a4ea0 100644
--- a/Help/command/message.rst
+++ b/Help/command/message.rst
@@ -14,6 +14,8 @@ Synopsis
`Reporting checks`_
message(<checkState> "message text" ...)
+ `Configure Log`_
+ message(CONFIGURE_LOG <text>...)
General messages
^^^^^^^^^^^^^^^^
@@ -193,3 +195,56 @@ Output from the above would appear something like the following::
-- Finding partB
-- Finding partB - not found
-- Finding my things - missing components: B
+
+Configure Log
+^^^^^^^^^^^^^
+
+.. versionadded:: 3.26
+
+.. code-block:: cmake
+
+ message(CONFIGURE_LOG <text>...)
+
+Record a :ref:`configure-log message event <message configure-log event>`
+with the specified ``<text>``. By convention, if the text contains more
+than one line, the first line should be a summary of the event.
+
+This mode is intended to record the details of a system inspection check
+or other one-time operation guarded by a cache entry, but that is not
+performed using :command:`try_compile` or :command:`try_run`, which
+automatically log their details. Projects should avoid calling it every
+time CMake runs. For example:
+
+.. code-block:: cmake
+
+ if (NOT DEFINED MY_CHECK_RESULT)
+ # Print check summary in configure output.
+ message(CHECK_START "My Check")
+
+ # ... perform system inspection, e.g., with execute_process ...
+
+ # Cache the result so we do not run the check again.
+ set(MY_CHECK_RESULT "${MY_CHECK_RESULT}" CACHE INTERNAL "My Check")
+
+ # Record the check details in the cmake-configure-log.
+ message(CONFIGURE_LOG
+ "My Check Result: ${MY_CHECK_RESULT}\n"
+ "${details}"
+ )
+
+ # Print check result in configure output.
+ if(MY_CHECK_RESULT)
+ message(CHECK_PASS "passed")
+ else()
+ message(CHECK_FAIL "failed")
+ endif()
+ endif()
+
+If no project is currently being configured, such as in
+:ref:`cmake -P <Script Processing Mode>` script mode,
+this command does nothing.
+
+See Also
+^^^^^^^^
+
+* :command:`cmake_language(GET_MESSAGE_LOG_LEVEL)`
diff --git a/Help/command/output_required_files.rst b/Help/command/output_required_files.rst
index b3a6e86..fbe5dbd 100644
--- a/Help/command/output_required_files.rst
+++ b/Help/command/output_required_files.rst
@@ -9,7 +9,7 @@ This command exists only because ancient CMake versions provided it.
CMake handles preprocessor dependency scanning automatically using a
more advanced scanner.
-::
+.. code-block:: cmake
output_required_files(srcfile outputfile)
diff --git a/Help/command/project.rst b/Help/command/project.rst
index 8f32fa3..ab93f3d 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -102,23 +102,9 @@ The options are:
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``, ``HIP``, ``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.
+.. include:: SUPPORTED_LANGUAGES.txt
- .. 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.
@@ -188,5 +174,6 @@ call exists, CMake will issue a warning and pretend there is a
Call the ``project()`` command near the top of the top-level
``CMakeLists.txt``, but *after* calling :command:`cmake_minimum_required`.
It is important to establish version and policy settings before invoking
- other commands whose behavior they may affect.
+ other commands whose behavior they may affect and for this reason the
+ ``project()`` command will issue a warning if this order is not kept.
See also policy :policy:`CMP0000`.
diff --git a/Help/command/remove.rst b/Help/command/remove.rst
index 543d016..e12a937 100644
--- a/Help/command/remove.rst
+++ b/Help/command/remove.rst
@@ -5,7 +5,7 @@ remove
Use the :command:`list(REMOVE_ITEM)` command instead.
-::
+.. code-block:: cmake
remove(VAR VALUE VALUE ...)
diff --git a/Help/command/return.rst b/Help/command/return.rst
index 3013b52..bb6d87d 100644
--- a/Help/command/return.rst
+++ b/Help/command/return.rst
@@ -30,7 +30,7 @@ command. All arguments are ignored unless that policy is set to ``NEW``.
with the :command:`block` command, as described below.
The ``PROPAGATE`` option can be very useful in conjunction with the
- :command:`block` command. A :command:`return` will propagate the
+ :command:`block` command. A ``return`` will propagate the
specified variables through any enclosing block scopes created by the
:command:`block` commands. Inside a function, this ensures the variables
are propagated to the function's caller, regardless of any blocks within
@@ -88,4 +88,5 @@ command. All arguments are ignored unless that policy is set to ``NEW``.
See Also
^^^^^^^^
- * :command:`block`
+* :command:`block`
+* :command:`function`
diff --git a/Help/command/set.rst b/Help/command/set.rst
index 90b57d2..c724844 100644
--- a/Help/command/set.rst
+++ b/Help/command/set.rst
@@ -111,3 +111,8 @@ environment variable.
Arguments after ``<value>`` are ignored. If extra arguments are found,
then an author warning is issued.
+
+See Also
+^^^^^^^^
+
+* :command:`unset`
diff --git a/Help/command/set_directory_properties.rst b/Help/command/set_directory_properties.rst
index f02a8e6..93ad39b 100644
--- a/Help/command/set_directory_properties.rst
+++ b/Help/command/set_directory_properties.rst
@@ -13,3 +13,10 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* :command:`get_directory_property`
+* the more general :command:`set_property` command
diff --git a/Help/command/set_property.rst b/Help/command/set_property.rst
index b9b12c4..d446a2d 100644
--- a/Help/command/set_property.rst
+++ b/Help/command/set_property.rst
@@ -107,10 +107,15 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* :command:`get_property`
+* The :manual:`cmake-properties(7)` manual for a list of properties
+ in each scope.
diff --git a/Help/command/set_source_files_properties.rst b/Help/command/set_source_files_properties.rst
index 61c69a2..d937b33 100644
--- a/Help/command/set_source_files_properties.rst
+++ b/Help/command/set_source_files_properties.rst
@@ -34,10 +34,15 @@ list.
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.
+
+See Also
+^^^^^^^^
+
+* :command:`define_property`
+* :command:`get_source_file_property`
+* :ref:`Source File Properties` for the list of properties known
+ to CMake
diff --git a/Help/command/set_target_properties.rst b/Help/command/set_target_properties.rst
index 597be23..856b92c 100644
--- a/Help/command/set_target_properties.rst
+++ b/Help/command/set_target_properties.rst
@@ -15,6 +15,10 @@ 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 Also
+^^^^^^^^
-See :ref:`Target Properties` for the list of properties known to CMake.
+* :command:`define_property`
+* :command:`get_target_property`
+* the more general :command:`set_property` command
+* :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
index eadde33..125e460 100644
--- a/Help/command/set_tests_properties.rst
+++ b/Help/command/set_tests_properties.rst
@@ -14,6 +14,10 @@ Test property values may be specified using
:manual:`generator expressions <cmake-generator-expressions(7)>`
for tests created by the :command:`add_test(NAME)` signature.
-See also the :command:`set_property(TEST)` command.
+See Also
+^^^^^^^^
-See :ref:`Test Properties` for the list of properties known to CMake.
+* :command:`add_test`
+* :command:`define_property`
+* the more general :command:`set_property` command
+* :ref:`Target Properties` for the list of properties known to CMake
diff --git a/Help/command/string.rst b/Help/command/string.rst
index 86136a6..c24b9bc 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -522,6 +522,17 @@ specifiers:
``%Y``
The current year.
+``%z``
+ .. versionadded:: 3.26
+
+ The offset of the time zone from UTC, in hours and minutes,
+ with format ``+hhmm`` or ``-hhmm``.
+
+``%Z``
+ .. versionadded:: 3.26
+
+ The time zone name.
+
Unknown format specifiers will be ignored and copied to the output
as-is.
diff --git a/Help/command/subdir_depends.rst b/Help/command/subdir_depends.rst
index 0c1b3c1..2115b33 100644
--- a/Help/command/subdir_depends.rst
+++ b/Help/command/subdir_depends.rst
@@ -5,7 +5,7 @@ Disallowed since version 3.0. See CMake Policy :policy:`CMP0029`.
Does nothing.
-::
+.. code-block:: cmake
subdir_depends(subdir dep1 dep2 ...)
diff --git a/Help/command/subdirs.rst b/Help/command/subdirs.rst
index 530951b..ecc6d1f 100644
--- a/Help/command/subdirs.rst
+++ b/Help/command/subdirs.rst
@@ -7,7 +7,7 @@ subdirs
Add a list of subdirectories to the build.
-::
+.. code-block:: cmake
subdirs(dir1 dir2 ...[EXCLUDE_FROM_ALL exclude_dir1 exclude_dir2 ...]
[PREORDER] )
diff --git a/Help/command/target_compile_definitions.rst b/Help/command/target_compile_definitions.rst
index 2d292af..2290efb 100644
--- a/Help/command/target_compile_definitions.rst
+++ b/Help/command/target_compile_definitions.rst
@@ -25,10 +25,8 @@ 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.
+.. |command_name| replace:: ``target_compile_definitions``
+.. include:: GENEX_NOTE.txt
Any leading ``-D`` on an item will be removed. Empty items are ignored.
For example, the following are all equivalent:
@@ -48,3 +46,16 @@ Definitions may optionally have values:
Note that many compilers treat ``-DFOO`` as equivalent to ``-DFOO=1``, but
other tools may not recognize this in all circumstances (e.g. IntelliSense).
+
+See Also
+^^^^^^^^
+
+* :command:`add_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_compile_features.rst b/Help/command/target_compile_features.rst
index 58502bf..531af81 100644
--- a/Help/command/target_compile_features.rst
+++ b/Help/command/target_compile_features.rst
@@ -30,8 +30,20 @@ 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.
+.. |command_name| replace:: ``target_compile_features``
+.. |more_see_also| replace:: See the :manual:`cmake-compile-features(7)`
+ manual for information on compile features and a list of supported compilers.
+.. include:: GENEX_NOTE.txt
+ :start-line: 1
+
+See Also
+^^^^^^^^
+
+* :command:`target_compile_definitions`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst
index 0d86c91..698f62d 100644
--- a/Help/command/target_compile_options.rst
+++ b/Help/command/target_compile_options.rst
@@ -19,7 +19,8 @@ Arguments
^^^^^^^^^
If ``BEFORE`` is specified, the content will be prepended to the property
-instead of being appended.
+instead of being appended. See policy :policy:`CMP0101` which affects
+whether ``BEFORE`` will be ignored in certain cases.
The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
specify the :ref:`scope <Target Usage Requirements>` of the following arguments.
@@ -32,21 +33,26 @@ The following arguments specify compile options. Repeated calls for the same
.. 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.
+.. |command_name| replace:: ``target_compile_options``
+.. include:: GENEX_NOTE.txt
.. 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`.
+* 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 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`.
+* For file-specific settings, there is the source file property :prop_sf:`COMPILE_OPTIONS`.
+
+* :command:`target_compile_features`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_include_directories.rst b/Help/command/target_include_directories.rst
index f13ff29..2a410ec 100644
--- a/Help/command/target_include_directories.rst
+++ b/Help/command/target_include_directories.rst
@@ -40,10 +40,8 @@ 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.
+.. |command_name| replace:: ``target_include_directories``
+.. include:: GENEX_NOTE.txt
Specified include directories may be absolute paths or relative paths.
A relative path will be interpreted as relative to the current source
@@ -74,3 +72,16 @@ Creating Relocatable Packages
.. |INTERFACE_PROPERTY_LINK| replace:: :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
.. include:: /include/INTERFACE_INCLUDE_DIRECTORIES_WARNING.txt
+
+See Also
+^^^^^^^^
+
+* :command:`include_directories`
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_link_directories.rst b/Help/command/target_link_directories.rst
index b72f746..2854c96 100644
--- a/Help/command/target_link_directories.rst
+++ b/Help/command/target_link_directories.rst
@@ -34,10 +34,8 @@ 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.
+.. |command_name| replace:: ``target_link_directories``
+.. include:: GENEX_NOTE.txt
.. note::
@@ -56,3 +54,16 @@ manual for more on defining buildsystem properties.
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``).
+
+See Also
+^^^^^^^^
+
+* :command:`link_directories`
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index bb7b5cc..1d27660 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -293,8 +293,8 @@ will be included in the link too.
.. _`Linking Object Libraries via $<TARGET_OBJECTS>`:
-Linking Object Libraries via $<TARGET_OBJECTS>
-""""""""""""""""""""""""""""""""""""""""""""""
+Linking Object Libraries via ``$<TARGET_OBJECTS>``
+""""""""""""""""""""""""""""""""""""""""""""""""""
.. versionadded:: 3.21
@@ -407,3 +407,15 @@ Creating Relocatable Packages
.. |INTERFACE_PROPERTY_LINK| replace:: :prop_tgt:`INTERFACE_LINK_LIBRARIES`
.. include:: /include/INTERFACE_LINK_LIBRARIES_WARNING.txt
+
+See Also
+^^^^^^^^
+
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst
index 3cd0e64..0d026f2 100644
--- a/Help/command/target_link_options.rst
+++ b/Help/command/target_link_options.rst
@@ -42,13 +42,23 @@ The following arguments specify link options. Repeated calls for the same
.. 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.
+.. |command_name| replace:: ``target_link_options``
+.. include:: GENEX_NOTE.txt
.. include:: DEVICE_LINK_OPTIONS.txt
.. include:: OPTIONS_SHELL.txt
.. include:: LINK_OPTIONS_LINKER.txt
+
+See Also
+^^^^^^^^
+
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_precompile_headers`
+* :command:`target_sources`
diff --git a/Help/command/target_precompile_headers.rst b/Help/command/target_precompile_headers.rst
index 84f5d12..8e5c0e9 100644
--- a/Help/command/target_precompile_headers.rst
+++ b/Help/command/target_precompile_headers.rst
@@ -70,17 +70,16 @@ included by absolute path. For example:
<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:
+.. |command_name| replace:: ``target_compile_features``
+.. |more_see_also| replace:: 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 :genex:`$<ANGLE-R>`. For example:
+.. include:: GENEX_NOTE.txt
+ :start-line: 1
.. code-block:: cmake
@@ -118,8 +117,17 @@ the ``REUSE_FROM`` form is used.
See Also
^^^^^^^^
-To disable precompile headers for specific targets, see the
-:prop_tgt:`DISABLE_PRECOMPILE_HEADERS` target property.
+* 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.
+* To prevent precompile headers from being used when compiling a specific
+ source file, see the :prop_sf:`SKIP_PRECOMPILE_HEADERS` source file property.
+
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_sources`
diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst
index 461175a..5d07f54 100644
--- a/Help/command/target_sources.rst
+++ b/Help/command/target_sources.rst
@@ -202,3 +202,17 @@ Target properties related to include directories are also modified by
of the file set is ``INTERFACE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of
the file set are wrapped in :genex:`$<BUILD_INTERFACE>` and appended to this
property.
+
+See Also
+^^^^^^^^
+
+* :command:`add_executable`
+* :command:`add_library`
+* :command:`target_compile_definitions`
+* :command:`target_compile_features`
+* :command:`target_compile_options`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+* :command:`target_link_directories`
+* :command:`target_link_options`
+* :command:`target_precompile_headers`
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index 9e9f39f..8abb6e0 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -14,18 +14,20 @@ Try Compiling Whole Projects
.. code-block:: cmake
- try_compile(<resultVar> PROJECT <projectName>
+ try_compile(<compileResultVar> PROJECT <projectName>
SOURCE_DIR <srcdir>
[BINARY_DIR <bindir>]
[TARGET <targetName>]
+ [LOG_DESCRIPTION <text>]
[NO_CACHE]
+ [NO_LOG]
[CMAKE_FLAGS <flags>...]
[OUTPUT_VARIABLE <var>])
.. versionadded:: 3.25
-Try building a project. The success or failure of the ``try_compile``,
-i.e. ``TRUE`` or ``FALSE`` respectively, is returned in ``<resultVar>``.
+Try building a project. Build success returns ``TRUE`` and build failure
+returns ``FALSE`` in ``<compileResultVar>``.
In this form, ``<srcdir>`` should contain a complete CMake project with a
``CMakeLists.txt`` file and all sources. The ``<bindir>`` and ``<srcdir>``
@@ -40,14 +42,18 @@ below for the meaning of other options.
Previously this was only done by the
:ref:`source file <Try Compiling Source Files>` signature.
-This command also supports an alternate signature
-which was present in older versions of CMake:
+.. versionadded:: 3.26
+ This command records a
+ :ref:`configure-log try_compile event <try_compile configure-log event>`
+ if the ``NO_LOG`` option is not specified.
+
+This command supports an alternate signature for CMake older than 3.25.
+The signature above is recommended for clarity.
.. code-block:: cmake
- try_compile(<resultVar> <bindir> <srcdir>
+ try_compile(<compileResultVar> <bindir> <srcdir>
<projectName> [<targetName>]
- [NO_CACHE]
[CMAKE_FLAGS <flags>...]
[OUTPUT_VARIABLE <var>])
@@ -58,12 +64,14 @@ Try Compiling Source Files
.. code-block:: cmake
- try_compile(<resultVar>
+ try_compile(<compileResultVar>
<SOURCES <srcfile...> |
SOURCE_FROM_CONTENT <name> <content> |
SOURCE_FROM_VAR <name> <var> |
SOURCE_FROM_FILE <name> <path> >...
+ [LOG_DESCRIPTION <text>]
[NO_CACHE]
+ [NO_LOG]
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
@@ -79,8 +87,8 @@ Try Compiling Source Files
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>``.
+variable). Build success returns ``TRUE`` and build failure returns ``FALSE``
+in ``<compileResultVar>``.
In this form, one or more source files must be provided. Additionally, one of
``SOURCES`` and/or ``SOURCE_FROM_*`` must precede other keywords.
@@ -105,17 +113,16 @@ contain something like the following:
CMake automatically generates, for each ``try_compile`` operation, a
unique directory under ``${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch``
with an unspecified name. These directories are cleaned automatically unless
-:option:`--debug-trycompile <cmake --debug-trycompile>` is passed to ``cmake``.
+:option:`--debug-trycompile <cmake --debug-trycompile>` is passed to :program:`cmake`.
Such directories from previous runs are also unconditionally cleaned at the
-beginning of any ``cmake`` execution.
+beginning of any :program:`cmake` execution.
-This command also supports an alternate signature
-which was present in older versions of CMake:
+This command supports an alternate signature for CMake older than 3.25.
+The signature above is recommended for clarity.
.. code-block:: cmake
- try_compile(<resultVar> <bindir> <srcfile|SOURCES srcfile...>
- [NO_CACHE]
+ try_compile(<compileResultVar> <bindir> <srcfile|SOURCES srcfile...>
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
@@ -130,7 +137,7 @@ which was present in older versions of CMake:
In this version, ``try_compile`` will use ``<bindir>/CMakeFiles/CMakeTmp`` for
its operation, and all such files will be cleaned automatically.
For debugging, :option:`--debug-trycompile <cmake --debug-trycompile>` can be
-passed to ``cmake`` to avoid this clean. However, multiple sequential
+passed to :program:`cmake` to avoid this clean. However, multiple sequential
``try_compile`` operations, if given the same ``<bindir>``, will reuse this
single output directory, such that you can only debug one such ``try_compile``
call at a time. Use of the newer signature is recommended to simplify
@@ -171,6 +178,12 @@ The options are:
set the :prop_tgt:`STATIC_LIBRARY_OPTIONS` target property in the generated
project, depending on the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable.
+``LOG_DESCRIPTION <text>``
+ .. versionadded:: 3.26
+
+ Specify a non-empty text description of the purpose of the check.
+ This is recorded in the :manual:`cmake-configure-log(7)` entry.
+
``NO_CACHE``
.. versionadded:: 3.25
@@ -191,6 +204,11 @@ The options are:
the test is part of a larger inspection), ``NO_CACHE`` may be useful to avoid
leaking the intermediate result variable into the cache.
+``NO_LOG``
+ .. versionadded:: 3.26
+
+ Do not record a :manual:`cmake-configure-log(7)` entry for this call.
+
``OUTPUT_VARIABLE <var>``
Store the output from the build process in the given variable.
@@ -271,13 +289,18 @@ Other Behavior Settings
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.
+ ``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.
+Set variable :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` to choose a build
+configuration:
+
+* For multi-config generators, this selects which configuration to build.
+
+* For single-config generators, this sets :variable:`CMAKE_BUILD_TYPE` in
+ the test project.
.. versionadded:: 3.6
Set the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable to specify
@@ -327,3 +350,8 @@ a build configuration.
If :policy:`CMP0141` is set to ``NEW``, one can use
:variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` to specify the MSVC debug
information format.
+
+See Also
+^^^^^^^^
+
+* :command:`try_run`
diff --git a/Help/command/try_run.rst b/Help/command/try_run.rst
index cd41a4b..3a4e203 100644
--- a/Help/command/try_run.rst
+++ b/Help/command/try_run.rst
@@ -17,7 +17,9 @@ Try Compiling and Running Source Files
SOURCE_FROM_CONTENT <name> <content> |
SOURCE_FROM_VAR <name> <var> |
SOURCE_FROM_FILE <name> <path> >...
+ [LOG_DESCRIPTION <text>]
[NO_CACHE]
+ [NO_LOG]
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
@@ -30,32 +32,36 @@ Try Compiling and Running Source Files
[RUN_OUTPUT_VARIABLE <var>]
[RUN_OUTPUT_STDOUT_VARIABLE <var>]
[RUN_OUTPUT_STDERR_VARIABLE <var>]
- [OUTPUT_VARIABLE <var>]
[WORKING_DIRECTORY <var>]
[ARGS <args>...]
)
.. versionadded:: 3.25
-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
-documentation of options common to both commands, and for information on how
-the test project is constructed to build the source file.
+Try building an executable from one or more source files. Build success
+returns ``TRUE`` and build failure returns ``FALSE`` in ``<compileResultVar>``.
+If the build succeeds, this runs the executable and stores the exit code in
+``<runResultVar>``. If the executable was built, but failed to run, then
+``<runResultVar>`` will be set to ``FAILED_TO_RUN``. See command
+:command:`try_compile` for documentation of options common to both commands,
+and for information on how the test project is constructed to build the source
+file.
One or more source files must be provided. Additionally, one of ``SOURCES``
and/or ``SOURCE_FROM_*`` must precede other keywords.
-This command also supports an alternate signature
-which was present in older versions of CMake:
+.. versionadded:: 3.26
+ This command records a
+ :ref:`configure-log try_run event <try_run configure-log event>`
+ if the ``NO_LOG`` option is not specified.
+
+This command supports an alternate signature for CMake older than 3.25.
+The signature above is recommended for clarity.
.. code-block:: cmake
try_run(<runResultVar> <compileResultVar>
<bindir> <srcfile|SOURCES srcfile...>
- [NO_CACHE]
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
@@ -66,8 +72,6 @@ which was present in older versions of CMake:
[<LANG>_STANDARD_REQUIRED <bool>]
[<LANG>_EXTENSIONS <bool>]
[RUN_OUTPUT_VARIABLE <var>]
- [RUN_OUTPUT_STDOUT_VARIABLE <var>]
- [RUN_OUTPUT_STDERR_VARIABLE <var>]
[OUTPUT_VARIABLE <var>]
[WORKING_DIRECTORY <var>]
[ARGS <args>...]
@@ -110,15 +114,19 @@ The options specific to ``try_run`` are:
Other Behavior Settings
^^^^^^^^^^^^^^^^^^^^^^^
-Set the :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` variable to choose
-a build configuration.
+Set variable :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` to choose a build
+configuration:
+
+* For multi-config generators, this selects which configuration to build.
+
+* For single-config generators, this sets :variable:`CMAKE_BUILD_TYPE` in
+ the test project.
Behavior when Cross Compiling
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 3.3
- Use ``CMAKE_CROSSCOMPILING_EMULATOR`` when running cross-compiled
- binaries.
+ 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
diff --git a/Help/command/unset.rst b/Help/command/unset.rst
index 7521052..1cd1398 100644
--- a/Help/command/unset.rst
+++ b/Help/command/unset.rst
@@ -39,3 +39,8 @@ 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.
+
+See Also
+^^^^^^^^
+
+* :command:`set`
diff --git a/Help/command/use_mangled_mesa.rst b/Help/command/use_mangled_mesa.rst
index 5b0e2ee..bc84bb3 100644
--- a/Help/command/use_mangled_mesa.rst
+++ b/Help/command/use_mangled_mesa.rst
@@ -5,7 +5,7 @@ Disallowed since version 3.0. See CMake Policy :policy:`CMP0030`.
Copy mesa headers for use in combination with system GL.
-::
+.. code-block:: cmake
use_mangled_mesa(PATH_TO_MESA OUTPUT_DIRECTORY)
diff --git a/Help/command/utility_source.rst b/Help/command/utility_source.rst
index 94d6a4e..3c2bf39 100644
--- a/Help/command/utility_source.rst
+++ b/Help/command/utility_source.rst
@@ -5,7 +5,7 @@ Disallowed since version 3.0. See CMake Policy :policy:`CMP0034`.
Specify the source tree of a third-party utility.
-::
+.. code-block:: cmake
utility_source(cache_entry executable_name
path_to_source [file1 file2 ...])
diff --git a/Help/command/variable_requires.rst b/Help/command/variable_requires.rst
index 322b154..1dbb02d 100644
--- a/Help/command/variable_requires.rst
+++ b/Help/command/variable_requires.rst
@@ -7,7 +7,7 @@ Use the :command:`if` command instead.
Assert satisfaction of an option's required variables.
-::
+.. code-block:: cmake
variable_requires(TEST_VARIABLE RESULT_VARIABLE
REQUIRED_VARIABLE1
diff --git a/Help/command/while.rst b/Help/command/while.rst
index 0bafae5..cb0fa2d 100644
--- a/Help/command/while.rst
+++ b/Help/command/while.rst
@@ -27,7 +27,7 @@ If used, it must be a verbatim repeat of the argument of the opening
See Also
^^^^^^^^
- * :command:`break`
- * :command:`continue`
- * :command:`foreach`
- * :command:`endwhile`
+* :command:`break`
+* :command:`continue`
+* :command:`foreach`
+* :command:`endwhile`
diff --git a/Help/command/write_file.rst b/Help/command/write_file.rst
index 4d476bd..4d0bc63 100644
--- a/Help/command/write_file.rst
+++ b/Help/command/write_file.rst
@@ -5,7 +5,7 @@ write_file
Use the :command:`file(WRITE)` command instead.
-::
+.. code-block:: cmake
write_file(filename "message to write"... [APPEND])
diff --git a/Help/cpack_gen/archive.rst b/Help/cpack_gen/archive.rst
index 9df3cc4..7f7921d 100644
--- a/Help/cpack_gen/archive.rst
+++ b/Help/cpack_gen/archive.rst
@@ -4,19 +4,19 @@ 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)
+ - 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.
+ 7Z and TXZ formats support.
.. versionadded:: 3.16
- ``TZST`` format support.
+ TZST format support.
When this generator is called from ``CPackSourceConfig.cmake`` (or through
the ``package_source`` target), then the generated archive will contain all
@@ -47,27 +47,34 @@ 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.
- Note that ``<component>`` is all uppercase in the variable name.
+ Package file name without extension.
- The default is ``<CPACK_PACKAGE_FILE_NAME>[-<component>]``, with spaces
- replaced by '-'.
+ :Default: The default is ``<CPACK_PACKAGE_FILE_NAME>[-<component>]``, with spaces
+ replaced by '-'.
+
+ The extension is determined from the archive format (see list above) and
+ automatically appended to the file name. Note that ``<component>`` is all
+ uppercase in the variable name.
.. versionadded:: 3.9
- Per-component ``CPACK_ARCHIVE_<component>_FILE_NAME`` variables.
+ Per-component :variable:`!CPACK_ARCHIVE_<component>_FILE_NAME` variables.
.. variable:: CPACK_ARCHIVE_FILE_EXTENSION
.. versionadded:: 3.25
- Package file extension. Default values are given in the list above.
+ Package file extension.
+
+ :Default: Default values are given in the list above.
.. 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.
+ Enable component packaging.
+
+ :Default: ``OFF``
+
+ If enabled (``ON``) multiple packages are generated. By default a single package
+ containing files of all components is generated.
Variables used by CPack Archive generator
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,15 +82,18 @@ 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`
+- :cpack_gen:`CPack Cygwin Generator`
+- :cpack_gen:`CPack FreeBSD Generator`
.. variable:: CPACK_ARCHIVE_THREADS
+ The number of threads to use when performing the compression.
+
.. 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.
+ :Default: ``1``
+
+ 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.
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
index 1514dbc..705ec9c 100644
--- a/Help/cpack_gen/deb.rst
+++ b/Help/cpack_gen/deb.rst
@@ -8,16 +8,16 @@ 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`.
+:variable:`!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.
+specifics :variable:`!CPACK_DEBIAN_XXX` variables.
-``CPACK_DEBIAN_<COMPONENT>_XXXX`` variables may be used in order to have
+:variable:`!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.
@@ -34,10 +34,10 @@ List of CPack DEB generator specific variables:
Enable component packaging for CPackDEB
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
- If enabled (ON) multiple packages are generated. By default a single package
+ If enabled (``ON``) multiple packages are generated. By default a single package
containing files of all components is generated.
.. variable:: CPACK_DEBIAN_PACKAGE_NAME
@@ -46,16 +46,16 @@ List of CPack DEB generator specific variables:
Set Package control field (variable is automatically transformed to lower
case).
- * Mandatory : YES
- * Default :
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_PACKAGE_NAME` for non-component based
installations
- - :variable:`CPACK_DEBIAN_PACKAGE_NAME` suffixed with -<COMPONENT>
+ - :variable:`CPACK_DEBIAN_PACKAGE_NAME` suffixed with ``-<COMPONENT>``
for component-based installations.
.. versionadded:: 3.5
- Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_NAME`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_NAME` variables.
See https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-source
@@ -66,8 +66,8 @@ List of CPack DEB generator specific variables:
Package file name.
- * Mandatory : YES
- * Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].deb``
+ :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::
@@ -98,8 +98,8 @@ List of CPack DEB generator specific variables:
The Debian package epoch
- * Mandatory : No
- * Default : -
+ :Mandatory: No
+ :Default: None
Optional number that should be incremented when changing versioning schemas
or fixing mistakes in the version numbers of older packages.
@@ -108,8 +108,8 @@ List of CPack DEB generator specific variables:
The Debian package version
- * Mandatory : YES
- * Default : :variable:`CPACK_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
@@ -130,8 +130,8 @@ List of CPack DEB generator specific variables:
The Debian package release - Debian revision number.
- * Mandatory : No
- * Default : -
+ :Mandatory: No
+ :Default: None
This is the numbering of the DEB package itself, i.e. the version of the
packaging and not the version of the content (see
@@ -144,20 +144,20 @@ List of CPack DEB generator specific variables:
The Debian package architecture
- * Mandatory : YES
- * Default : Output of ``dpkg --print-architecture`` (or ``i386``
+ :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.
+ Per-component :variable:`!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 :
+ :Mandatory: No
+ :Default:
- An empty string for non-component based installations
- :variable:`CPACK_DEBIAN_PACKAGE_DEPENDS` for component-based
@@ -165,7 +165,7 @@ List of CPack DEB generator specific variables:
.. versionadded:: 3.3
- Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_DEPENDS` variables.
.. note::
@@ -178,7 +178,9 @@ List of CPack DEB generator specific variables:
only the automatically discovered dependencies will be set for this
component.
- Example::
+ Example:
+
+ .. code-block:: cmake
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libc6 (< 2.4)")
@@ -189,23 +191,23 @@ List of CPack DEB generator specific variables:
Sets inter-component dependencies if listed with
:variable:`CPACK_COMPONENT_<compName>_DEPENDS` variables.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_DEBIAN_PACKAGE_MAINTAINER
The Debian package maintainer
- * Mandatory : YES
- * Default : ``CPACK_PACKAGE_CONTACT``
+ :Mandatory: Yes
+ :Default: :variable:`!CPACK_PACKAGE_CONTACT`
.. variable:: CPACK_DEBIAN_PACKAGE_DESCRIPTION
CPACK_DEBIAN_<COMPONENT>_DESCRIPTION
The Debian package description
- * Mandatory : YES
- * Default :
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_DEBIAN_<COMPONENT>_DESCRIPTION` (component
based installers only) if set, or :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` if set, or
@@ -218,13 +220,13 @@ List of CPack DEB generator specific variables:
line of description as defined in `Debian Policy Manual`_.
.. versionadded:: 3.3
- Per-component ``CPACK_COMPONENT_<compName>_DESCRIPTION`` variables.
+ Per-component :variable:`!CPACK_COMPONENT_<compName>_DESCRIPTION` variables.
.. versionadded:: 3.16
- Per-component ``CPACK_DEBIAN_<COMPONENT>_DESCRIPTION`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_DESCRIPTION` variables.
.. versionadded:: 3.16
- The ``CPACK_PACKAGE_DESCRIPTION_FILE`` variable.
+ The :variable:`!CPACK_PACKAGE_DESCRIPTION_FILE` variable.
.. _Debian Policy Manual: https://www.debian.org/doc/debian-policy/ch-controlfields.html#description
@@ -233,11 +235,11 @@ List of CPack DEB generator specific variables:
Set Section control field e.g. admin, devel, doc, ...
- * Mandatory : YES
- * Default : "devel"
+ :Mandatory: Yes
+ :Default: ``devel``
.. versionadded:: 3.5
- Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_SECTION` variables.
See https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
@@ -249,12 +251,10 @@ List of CPack DEB generator specific variables:
The archive format used for creating the Debian package.
- * Mandatory : YES
- * Default : "gnutar"
-
- Possible value is:
+ :Mandatory: Yes
+ :Default: ``gnutar``
- - gnutar
+ Possible value is: ``gnutar``
.. note::
@@ -269,8 +269,8 @@ List of CPack DEB generator specific variables:
The compression used for creating the Debian package.
- * Mandatory : YES
- * Default : "gzip"
+ :Mandatory: Yes
+ :Default: ``gzip``
Possible values are:
@@ -298,11 +298,11 @@ List of CPack DEB generator specific variables:
Set Priority control field e.g. required, important, standard, optional,
extra
- * Mandatory : YES
- * Default : "optional"
+ :Mandatory: Yes
+ :Default: ``optional``
.. versionadded:: 3.5
- Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY` variables.
See https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities
@@ -312,11 +312,11 @@ List of CPack DEB generator specific variables:
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`
+ :Mandatory: No
+ :Default: :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
.. versionadded:: 3.12
- The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+ The :variable:`!CMAKE_PROJECT_HOMEPAGE_URL` variable.
.. note::
@@ -329,11 +329,11 @@ List of CPack DEB generator specific variables:
May be set to ON in order to use ``dpkg-shlibdeps`` to generate
better package dependency list.
- * Mandatory : NO
- * Default :
+ :Mandatory: No
+ :Default:
- :variable:`CPACK_DEBIAN_PACKAGE_SHLIBDEPS` if set or
- - OFF
+ - ``OFF``
.. note::
@@ -350,7 +350,7 @@ List of CPack DEB generator specific variables:
shared libraries that could not get resolved otherwise.
.. versionadded:: 3.3
- Per-component ``CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS`` variables.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_SHLIBDEPS` variables.
.. versionadded:: 3.6
Correct handling of ``$ORIGIN`` in :variable:`CMAKE_INSTALL_RPATH`.
@@ -363,8 +363,8 @@ List of CPack DEB generator specific variables:
via its ``-l`` option. These will be searched by ``dpkg-shlibdeps`` in order
to find private shared library dependencies.
- * Mandatory : NO
- * Default :
+ :Mandatory: No
+ :Default: None
.. note::
@@ -377,8 +377,8 @@ List of CPack DEB generator specific variables:
May be set when invoking cpack in order to trace debug information
during the CPack DEB generator run.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_DEBIAN_PACKAGE_PREDEPENDS
CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS
@@ -389,58 +389,58 @@ List of CPack DEB generator specific variables:
before even starting the installation of the package which declares the
pre-dependency.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_PREDEPENDS` variables.
See https://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.
+ 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 :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_ENHANCES` variables.
See https://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.
+ 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
+ ``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 :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_BREAKS` variables.
See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-breaks
@@ -452,15 +452,15 @@ List of CPack DEB generator specific variables:
field, ``dpkg`` will not allow them to be unpacked on the system at
the same time.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONFLICTS` variables.
See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts
@@ -479,15 +479,15 @@ List of CPack DEB generator specific variables:
A virtual package is one which appears in the `Provides` control field of
another package.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_PROVIDES` variables.
See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-virtual
@@ -498,34 +498,34 @@ List of CPack DEB generator specific variables:
Packages can declare in their control file that they should overwrite
files in certain other packages, or completely replace other packages.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_REPLACES` variables.
See https://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.
+ Sets the ``Recommends`` field of the Debian package.
Allows packages to declare a strong, but not absolute, dependency on other
packages.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_RECOMMENDS` variables.
See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
@@ -535,15 +535,15 @@ List of CPack DEB generator specific variables:
Sets the `Suggests` field of the Debian package.
Allows packages to declare a suggested package install grouping.
- * Mandatory : NO
- * Default :
+ :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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_SUGGESTS` variables.
See https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
@@ -551,8 +551,8 @@ List of CPack DEB generator specific variables:
.. versionadded:: 3.6
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
Allows to generate shlibs control file automatically. Compatibility is defined by
:variable:`CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY` variable value.
@@ -569,11 +569,11 @@ List of CPack DEB generator specific variables:
Compatibility policy for auto-generated shlibs control file.
- * Mandatory : NO
- * Default : "="
+ :Mandatory: No
+ :Default: ``=``
Defines compatibility policy for auto-generated shlibs control file.
- Possible values: "=", ">="
+ Possible values: ``=``, ``>=``
See https://www.debian.org/doc/debian-policy/ch-sharedlibs.html#s-sharedlibs-shlibdeps
@@ -584,16 +584,18 @@ List of CPack DEB generator specific variables:
control.tar.gz.
Typical usage is for conffiles, postinst, postrm, prerm.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
- Usage::
+ Usage:
+
+ .. code-block:: cmake
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.
+ Per-component :variable:`!CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_EXTRA` variables.
.. variable:: CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION
CPACK_DEBIAN_<COMPONENT>_PACKAGE_CONTROL_STRICT_PERMISSION
@@ -603,10 +605,12 @@ List of CPack DEB generator specific variables:
This variable indicates if the Debian policy on control files should be
strictly followed.
- * Mandatory : NO
- * Default : FALSE
+ :Mandatory: No
+ :Default: ``FALSE``
+
+ Usage:
- Usage::
+ .. code-block:: cmake
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
@@ -632,8 +636,8 @@ List of CPack DEB generator specific variables:
source) the source from which the binary has been generated should be
indicated with the field ``Source``.
- * Mandatory : NO
- * Default :
+ :Mandatory: No
+ :Default:
- An empty string for non-component based installations
- :variable:`CPACK_DEBIAN_PACKAGE_SOURCE` for component-based
@@ -660,8 +664,8 @@ Dbgsym packaging has its own set of variables:
Enable generation of dbgsym .ddeb package(s).
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
.. note::
@@ -683,7 +687,7 @@ 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
+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
@@ -694,7 +698,7 @@ Reproducible packages
.. versionadded:: 3.13
-The environment variable ``SOURCE_DATE_EPOCH`` may be set to a UNIX
+The environment variable :envvar:`!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
index cba7a00..0bd52ec 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -11,14 +11,19 @@ on macOS:
.. variable:: CPACK_DMG_VOLUME_NAME
- The volume name of the generated disk image. Defaults to
- CPACK_PACKAGE_FILE_NAME.
+ The volume name of the generated disk image.
+
+ :Default: :variable:`CPACK_PACKAGE_FILE_NAME`
.. variable:: CPACK_DMG_FORMAT
- The disk image format. Common values are ``UDRO`` (UDIF read-only), ``UDZO`` (UDIF
+ The disk image format.
+
+ :Default: ``UDZO``
+
+ 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``.
+ more information on other available formats.
.. variable:: CPACK_DMG_DS_STORE
@@ -41,6 +46,8 @@ on macOS:
.. variable:: CPACK_DMG_BACKGROUND_IMAGE
+ :Default:
+
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
@@ -58,13 +65,15 @@ on macOS:
.. versionadded:: 3.23
+ :Default: ``OFF``
+
Control whether :variable:`CPACK_RESOURCE_FILE_LICENSE`, if set to a
non-default value, is used as the license agreement provided when
- mounting the DMG. If ``CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE`` is
+ mounting the DMG. If :variable:`!CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE` is
not set, :manual:`cpack(1)` defaults to off.
In a CMake project that uses the :module:`CPack` module to generate
- ``CPackConfig.cmake``, ``CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE``
+ ``CPackConfig.cmake``, :variable:`!CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE`
must be explicitly enabled by the project to activate the SLA.
See policy :policy:`CMP0133`.
@@ -82,8 +91,8 @@ on macOS:
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
+ language defined in :variable:`CPACK_DMG_SLA_LANGUAGES`. If both this variable and
+ :variable:`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.
@@ -120,17 +129,18 @@ on macOS:
.. versionadded:: 3.17
File name when packaging ``<component>`` as its own DMG
- (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
+ (:variable:`CPACK_COMPONENTS_GROUPING` set to ``IGNORE``).
- - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
+ :Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
.. variable:: CPACK_DMG_FILESYSTEM
.. versionadded:: 3.21
+ :Default: ``HFS+``
+
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
diff --git a/Help/cpack_gen/freebsd.rst b/Help/cpack_gen/freebsd.rst
index faf8c74..e97ba49 100644
--- a/Help/cpack_gen/freebsd.rst
+++ b/Help/cpack_gen/freebsd.rst
@@ -19,7 +19,7 @@ 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
+:variable:`!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.
@@ -28,14 +28,14 @@ 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
+:variable:`!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
+that use general settings (e.g. :variable:`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
@@ -46,8 +46,8 @@ the RPM information (e.g. package license).
Sets the package name (in the package manifest, but also affects the
output filename).
- * Mandatory: YES
- * Default:
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_PACKAGE_NAME` (this is always set by CPack itself,
based on CMAKE_PROJECT_NAME).
@@ -57,8 +57,8 @@ the RPM information (e.g. package license).
Sets the package comment. This is the short description displayed by
pkg(8) in standard "pkg info" output.
- * Mandatory: YES
- * Default:
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY` (this is always set
by CPack itself, if nothing else sets it explicitly).
@@ -68,14 +68,14 @@ the RPM information (e.g. package license).
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:
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_DEBIAN_PACKAGE_DESCRIPTION` (this may be set already
for Debian packaging, so it is used as a fallback).
- :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
+ - :variable:`PROJECT_DESCRIPTION` (this can be set with the ``DESCRIPTION``
parameter for :command:`project`).
.. variable:: CPACK_FREEBSD_PACKAGE_WWW
@@ -84,15 +84,15 @@ the RPM information (e.g. package license).
site from which the original source can be obtained and any additional
upstream documentation or information may be found.
- * Mandatory: YES
- * Default:
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_PACKAGE_HOMEPAGE_URL`, or if that is not set,
- :variable:`CPACK_DEBIAN_PACKAGE_HOMEPAGE` (this may be set already
for Debian packaging, so it is used as a fallback).
.. versionadded:: 3.12
- The ``CPACK_PACKAGE_HOMEPAGE_URL`` variable.
+ The :variable:`!CPACK_PACKAGE_HOMEPAGE_URL` variable.
.. variable:: CPACK_FREEBSD_PACKAGE_LICENSE
@@ -100,8 +100,8 @@ the RPM information (e.g. package license).
be one or more license-identifiers that pkg recognizes as acceptable license
identifiers (e.g. "GPLv2").
- * Mandatory: YES
- * Default:
+ :Mandatory: Yes
+ :Default:
- :variable:`CPACK_RPM_PACKAGE_LICENSE`
@@ -112,24 +112,24 @@ the RPM information (e.g. package 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
+ :Mandatory: No
+ :Default: single
.. variable:: CPACK_FREEBSD_PACKAGE_MAINTAINER
- The FreeBSD maintainer (e.g. kde@freebsd.org) of this package.
+ The FreeBSD maintainer (e.g. ``kde@freebsd.org``) of this package.
- * Mandatory: YES
- * Default: none
+ :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.
+ puts the package somewhere under ``misc/``, as a stopgap.
- * Mandatory: YES
- * Default: misc/<package name>
+ :Mandatory: Yes
+ :Default: ``misc/<package name>``
.. variable:: CPACK_FREEBSD_PACKAGE_CATEGORIES
@@ -137,15 +137,15 @@ the RPM information (e.g. package license).
from ports). If none is set a single category is determined based on
the package origin.
- * Mandatory: YES
- * Default: derived from 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.
+ 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
+ :Mandatory: No
+ :Default: empty
diff --git a/Help/cpack_gen/nuget.rst b/Help/cpack_gen/nuget.rst
index 3bf7f84..1f2e762 100644
--- a/Help/cpack_gen/nuget.rst
+++ b/Help/cpack_gen/nuget.rst
@@ -5,11 +5,11 @@ CPack NuGet Generator
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
+is no :variable:`!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.
+(:variable:`CPACK_INCLUDE_TOPLEVEL_DIRECTORY`) is ignored by this generator.
Variables specific to CPack NuGet generator
@@ -17,10 +17,10 @@ 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`.
+it uses the :variable:`!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
+specifics :variable:`!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).
@@ -31,8 +31,8 @@ List of CPack NuGet generator specific variables:
Enable component packaging for CPack NuGet generator
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
.. variable:: CPACK_NUGET_PACKAGE_NAME
CPACK_NUGET_<compName>_PACKAGE_NAME
@@ -40,26 +40,27 @@ List of CPack NuGet generator specific variables:
The NUGET package name. ``CPACK_NUGET_PACKAGE_NAME`` is used as the
package ``id`` on nuget.org_
- * Mandatory : YES
- * Default : :variable:`CPACK_PACKAGE_NAME`
+ :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`
+ :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 :
+ :Mandatory: Yes
+ :Default:
+
- :variable:`CPACK_COMPONENT_<compName>_DESCRIPTION`,
- - ``CPACK_COMPONENT_GROUP_<groupName>_DESCRIPTION``,
+ - :variable:`!CPACK_COMPONENT_GROUP_<groupName>_DESCRIPTION`,
- :variable:`CPACK_PACKAGE_DESCRIPTION`
.. variable:: CPACK_NUGET_PACKAGE_AUTHORS
@@ -70,8 +71,8 @@ List of CPack NuGet generator specific variables:
nuget.org_ and are used to cross-reference packages by the same
authors.
- * Mandatory : YES
- * Default : :variable:`CPACK_PACKAGE_VENDOR`
+ :Mandatory: Yes
+ :Default: :variable:`CPACK_PACKAGE_VENDOR`
.. variable:: CPACK_NUGET_PACKAGE_TITLE
CPACK_NUGET_<compName>_PACKAGE_TITLE
@@ -80,10 +81,11 @@ List of CPack NuGet generator specific variables:
as on nuget.org_ and the Package Manager in Visual Studio. If not
specified, the package ID is used.
- * Mandatory : NO
- * Default :
+ :Mandatory: No
+ :Default:
+
- :variable:`CPACK_COMPONENT_<compName>_DISPLAY_NAME`,
- - ``CPACK_COMPONENT_GROUP_<groupName>_DISPLAY_NAME``
+ - :variable:`!CPACK_COMPONENT_GROUP_<groupName>_DISPLAY_NAME`
.. variable:: CPACK_NUGET_PACKAGE_OWNERS
CPACK_NUGET_<compName>_PACKAGE_OWNERS
@@ -92,8 +94,8 @@ List of CPack NuGet generator specific variables:
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 : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_HOMEPAGE_URL
CPACK_NUGET_<compName>_PACKAGE_HOMEPAGE_URL
@@ -101,8 +103,8 @@ List of CPack NuGet generator specific variables:
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`
+ :Mandatory: No
+ :Default: :variable:`CPACK_PACKAGE_HOMEPAGE_URL`
.. variable:: CPACK_NUGET_PACKAGE_LICENSEURL
CPACK_NUGET_<compName>_PACKAGE_LICENSEURL
@@ -116,8 +118,8 @@ List of CPack NuGet generator specific variables:
An URL for the package's license, often shown in UI displays as well
as on nuget.org_.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION
CPACK_NUGET_<compName>_PACKAGE_LICENSE_EXPRESSION
@@ -131,24 +133,24 @@ List of CPack NuGet generator specific variables:
``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.
+ If :variable:`CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME` is specified,
+ :variable:`!CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION` is ignored.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. 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.
+ If :variable:`!CPACK_NUGET_PACKAGE_LICENSE_FILE_NAME` is specified,
+ :variable:`!CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION` is ignored.
.. versionadded:: 3.20
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_ICONURL
CPACK_NUGET_<compName>_PACKAGE_ICONURL
@@ -159,16 +161,16 @@ List of CPack NuGet generator specific variables:
An URL for a 64x64 image with transparency background to use as the
icon for the package in UI display.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_REQUIRE_LICENSE_ACCEPTANCE
When set to a true value, the user will be prompted to accept the license
before installing the package.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_ICON
CPACK_NUGET_<compName>_PACKAGE_ICON
@@ -178,8 +180,8 @@ List of CPack NuGet generator specific variables:
The filename of a 64x64 image with transparency background to use as the
icon for the package in UI display.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_DESCRIPTION_SUMMARY
CPACK_NUGET_<compName>_PACKAGE_DESCRIPTION_SUMMARY
@@ -187,8 +189,8 @@ List of CPack NuGet generator specific variables:
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`
+ :Mandatory: No
+ :Default: :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
.. variable:: CPACK_NUGET_PACKAGE_RELEASE_NOTES
CPACK_NUGET_<compName>_PACKAGE_RELEASE_NOTES
@@ -197,16 +199,16 @@ List of CPack NuGet generator specific variables:
often used in UI like the Updates tab of the Visual Studio Package
Manager in place of the package description.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_COPYRIGHT
CPACK_NUGET_<compName>_PACKAGE_COPYRIGHT
Copyright details for the package.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_LANGUAGE
CPACK_NUGET_<compName>_PACKAGE_LANGUAGE
@@ -215,8 +217,8 @@ List of CPack NuGet generator specific variables:
Locale specifier for the package, for example ``en_CA``.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_TAGS
CPACK_NUGET_<compName>_PACKAGE_TAGS
@@ -225,34 +227,33 @@ List of CPack NuGet generator specific variables:
package and aid discoverability of packages through search and
filtering.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_DEPENDENCIES
CPACK_NUGET_<compName>_PACKAGE_DEPENDENCIES
A list of package dependencies.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. 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.
+ transformed with :command:`string(MAKE_C_IDENTIFIER)` command.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: None
.. variable:: CPACK_NUGET_PACKAGE_DEBUG
Enable debug messages while executing CPack NuGet generator.
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
.. _nuget.org: https://www.nuget.org
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index b1e0077..7b91261 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -8,27 +8,27 @@ 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`.
+:variable:`!CPACK_XXX` variables used by :module:`CPack`.
The CPack RPM generator has specific features which are controlled by the specifics
-``CPACK_RPM_XXX`` variables.
+:variable:`!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
+:variable:`!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
+a component GROUP name. Usually, those variables correspond to RPM spec file
entities. One may find information about spec files here
-https://rpm.org/documentation
+https://rpm.org/documentation.
.. 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.
+ component is named ``foo`` then use :variable:`!CPACK_RPM_FOO_XXXX` variable
+ name format) as is with other :variable:`!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
+ :variable:`!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.
@@ -45,8 +45,8 @@ List of CPack RPM generator specific variables:
Enable component packaging for CPack RPM generator
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
If enabled (``ON``) multiple packages are generated. By default
a single package containing files of all components is generated.
@@ -56,22 +56,22 @@ List of CPack RPM generator specific variables:
The RPM package summary.
- * Mandatory : YES
- * Default : :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
+ :Mandatory: Yes
+ :Default: :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`
.. versionadded:: 3.2
- Per-component ``CPACK_RPM_<component>_PACKAGE_SUMMARY`` variables.
+ Per-component :variable:`!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`
+ :Mandatory: Yes
+ :Default: :variable:`CPACK_PACKAGE_NAME`
.. versionadded:: 3.5
- Per-component ``CPACK_RPM_<component>_PACKAGE_NAME`` variables.
+ Per-component :variable:`!CPACK_RPM_<component>_PACKAGE_NAME` variables.
.. variable:: CPACK_RPM_FILE_NAME
CPACK_RPM_<component>_FILE_NAME
@@ -80,8 +80,8 @@ List of CPack RPM generator specific variables:
Package file name.
- * Mandatory : YES
- * Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
+ :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
@@ -105,8 +105,8 @@ List of CPack RPM generator specific variables:
Main component that is packaged without component suffix.
- * Mandatory : NO
- * Default : -
+ :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
@@ -118,8 +118,8 @@ List of CPack RPM generator specific variables:
The RPM package epoch
- * Mandatory : No
- * Default : -
+ :Mandatory: No
+ :Default:
Optional number that should be incremented when changing versioning schemas
or fixing mistakes in the version numbers of older packages.
@@ -128,28 +128,28 @@ List of CPack RPM generator specific variables:
The RPM package version.
- * Mandatory : YES
- * Default : :variable:`CPACK_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``
+ :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.
+ Per-component :variable:`!CPACK_RPM_<component>_PACKAGE_ARCHITECTURE` variables.
.. variable:: CPACK_RPM_PACKAGE_RELEASE
The RPM package release.
- * Mandatory : YES
- * Default : 1
+ :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
@@ -169,8 +169,8 @@ List of CPack RPM generator specific variables:
The dist tag that is added RPM ``Release:`` field.
- * Mandatory : NO
- * Default : OFF
+ :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
@@ -180,57 +180,61 @@ List of CPack RPM generator specific variables:
The RPM package license policy.
- * Mandatory : YES
- * Default : "unknown"
+ :Mandatory: Yes
+ :Default: "unknown"
.. variable:: CPACK_RPM_PACKAGE_GROUP
CPACK_RPM_<component>_PACKAGE_GROUP
The RPM package group.
- * Mandatory : YES
- * Default : "unknown"
+ :Mandatory: Yes
+ :Default: "unknown"
.. versionadded:: 3.5
- Per-component ``CPACK_RPM_<component>_PACKAGE_GROUP`` variables.
+ Per-component :variable:`!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"
+ :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`
+ :Mandatory: No
+ :Default: :variable:`CMAKE_PROJECT_HOMEPAGE_URL`
.. versionadded:: 3.12
- The ``CMAKE_PROJECT_HOMEPAGE_URL`` variable.
+ The :variable:`!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"
+ :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.
+ Per-component :variable:`!CPACK_RPM_<component>_PACKAGE_DESCRIPTION` variables.
.. variable:: CPACK_RPM_COMPRESSION_TYPE
RPM compression type.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default: (system 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``
@@ -239,18 +243,25 @@ List of CPack RPM generator specific variables:
Possible values are:
- - lzma
- - xz
- - bzip2
- - gzip
+ ``lzma``
+ Lempel–Ziv–Markov chain algorithm
+
+ ``xz``
+ XZ Utils compression
+
+ ``bzip2``
+ bzip2 Burrows–Wheeler algorithm
+
+ ``gzip``
+ GNU Gzip compression
.. variable:: CPACK_RPM_PACKAGE_AUTOREQ
CPACK_RPM_<component>_PACKAGE_AUTOREQ
RPM spec autoreq field.
- * Mandatory : NO
- * Default : -
+ :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.
@@ -264,8 +275,8 @@ List of CPack RPM generator specific variables:
RPM spec autoprov field.
- * Mandatory : NO
- * Default : -
+ :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.
@@ -280,8 +291,8 @@ List of CPack RPM generator specific variables:
RPM spec autoreqprov field.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
Variable enables/disables autoreq and autoprov at the same time.
See :variable:`CPACK_RPM_PACKAGE_AUTOREQ` and
@@ -296,11 +307,13 @@ List of CPack RPM generator specific variables:
RPM spec requires field.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to set RPM dependencies (requires). Note that you must enclose
- the complete requires string between quotes, for example::
+ the complete requires string between quotes, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_REQUIRES "python >= 2.5.0, cmake >= 2.8")
@@ -313,11 +326,13 @@ List of CPack RPM generator specific variables:
RPM spec conflicts field.
- * Mandatory : NO
- * Default : -
+ :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::
+ enclose the complete requires string between quotes, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_CONFLICTS "libxml2")
@@ -332,11 +347,13 @@ List of CPack RPM generator specific variables:
RPM spec requires(pre) field.
- * Mandatory : NO
- * Default : -
+ :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::
+ you must enclose the complete requires string between quotes, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils, initscripts")
@@ -347,11 +364,13 @@ List of CPack RPM generator specific variables:
RPM spec requires(post) field.
- * Mandatory : NO
- * Default : -
+ :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::
+ you must enclose the complete requires string between quotes, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_REQUIRES_POST "shadow-utils, initscripts")
@@ -362,12 +381,14 @@ List of CPack RPM generator specific variables:
RPM spec requires(postun) field.
- * Mandatory : NO
- * Default : -
+ :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::
+ example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_REQUIRES_POSTUN "shadow-utils, initscripts")
@@ -378,11 +399,13 @@ List of CPack RPM generator specific variables:
RPM spec requires(preun) field.
- * Mandatory : NO
- * Default : -
+ :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::
+ you must enclose the complete requires string between quotes, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_PACKAGE_REQUIRES_PREUN "shadow-utils, initscripts")
@@ -391,8 +414,8 @@ List of CPack RPM generator specific variables:
RPM spec suggest field.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to set weak RPM dependencies (suggests). If ``rpmbuild`` doesn't
support the ``Suggests`` tag, CPack will emit a warning and ignore this
@@ -404,8 +427,8 @@ List of CPack RPM generator specific variables:
RPM spec provides field.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to set RPM dependencies (provides). The provided package list
of an RPM file could be printed with::
@@ -417,8 +440,8 @@ List of CPack RPM generator specific variables:
RPM spec obsoletes field.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to set RPM packages that are obsoleted by this one.
@@ -426,8 +449,8 @@ List of CPack RPM generator specific variables:
build a relocatable RPM.
- * Mandatory : NO
- * Default : CPACK_PACKAGE_RELOCATABLE
+ :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
@@ -442,11 +465,10 @@ List of CPack RPM generator specific variables:
.. variable:: CPACK_RPM_SPEC_INSTALL_POST
- Deprecated - use :variable:`CPACK_RPM_SPEC_MORE_DEFINE` instead.
+ .. deprecated:: 2.8.12 Use :variable:`CPACK_RPM_SPEC_MORE_DEFINE` instead.
- * Mandatory : NO
- * Default : -
- * Deprecated: YES
+ :Mandatory: No
+ :Default:
May be used to override the ``__spec_install_post`` section within the
generated spec file. This affects the install step during package creation,
@@ -458,12 +480,14 @@ List of CPack RPM generator specific variables:
RPM extended spec definitions lines.
- * Mandatory : NO
- * Default : -
+ :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)::
+ this may also disable other default post install processing):
+
+ .. code-block:: cmake
set(CPACK_RPM_SPEC_MORE_DEFINE "%define __spec_install_post /bin/true")
@@ -471,8 +495,8 @@ List of CPack RPM generator specific variables:
Toggle CPack RPM generator debug output.
- * Mandatory : NO
- * Default : -
+ :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::
@@ -484,8 +508,8 @@ List of CPack RPM generator specific variables:
A user provided spec file.
- * Mandatory : NO
- * Default : -
+ :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.
@@ -495,8 +519,8 @@ List of CPack RPM generator specific variables:
Spec file template.
- * Mandatory : NO
- * Default : -
+ :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::
@@ -513,23 +537,23 @@ List of CPack RPM generator specific variables:
Path to file containing pre install/uninstall/transaction script.
- * Mandatory : NO
- * Default : -
+ :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``
+ :variable:`!CPACK_RPM_<COMPONENT>_PRE_INSTALL_SCRIPT_FILE`,
+ :variable:`!CPACK_RPM_<COMPONENT>_PRE_UNINSTALL_SCRIPT_FILE`, and
+ :variable:`!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.
+ The :variable:`!CPACK_RPM_PRE_TRANS_SCRIPT_FILE` variable.
.. variable:: CPACK_RPM_POST_INSTALL_SCRIPT_FILE
CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
@@ -537,35 +561,35 @@ List of CPack RPM generator specific variables:
Path to file containing post install/uninstall/transaction script.
- * Mandatory : NO
- * Default : -
+ :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``
+ :variable:`!CPACK_RPM_<COMPONENT>_POST_INSTALL_SCRIPT_FILE`,
+ :variable:`!CPACK_RPM_<COMPONENT>_POST_UNINSTALL_SCRIPT_FILE`, and
+ :variable:`!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.
+ The :variable:`!CPACK_RPM_POST_TRANS_SCRIPT_FILE` variable.
.. variable:: CPACK_RPM_USER_FILELIST
CPACK_RPM_<COMPONENT>_USER_FILELIST
- * Mandatory : NO
- * Default : -
+ :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
+ user specified files of the :variable:`!CPACK_RPM_<COMPONENT>_USER_FILELIST` list will
be removed from the generated list. If referring to directories do
not add a trailing slash.
@@ -577,8 +601,8 @@ List of CPack RPM generator specific variables:
RPM changelog file.
- * Mandatory : NO
- * Default : -
+ :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``
@@ -588,10 +612,20 @@ List of CPack RPM generator specific variables:
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
+ :Mandatory: No
+ :Default:
+ The following paths are excluded by 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
@@ -607,8 +641,8 @@ List of CPack RPM generator specific variables:
additional list of path to be excluded.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to add more exclude path (directories or files) from the initial
default list of excluded paths. See
@@ -620,8 +654,8 @@ List of CPack RPM generator specific variables:
Packages relocation paths list.
- * Mandatory : NO
- * Default : -
+ :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
@@ -637,7 +671,7 @@ List of CPack RPM generator specific variables:
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.
+ out an :command:`AUTHOR_WARNING <message>` that RPM will be partially relocatable.
.. variable:: CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
@@ -645,8 +679,8 @@ List of CPack RPM generator specific variables:
Per component relocation path install prefix.
- * Mandatory : NO
- * Default : CPACK_PACKAGING_INSTALL_PREFIX
+ :Mandatory: No
+ :Default: :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
May be used to set per component :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
for relocatable RPM packages.
@@ -658,19 +692,33 @@ List of CPack RPM generator specific variables:
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
+ :Mandatory: No
+ :Default: :variable:`CPACK_PACKAGING_INSTALL_PREFIX` or
+ :variable:`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
+ May be used to remove :variable:`CPACK_PACKAGING_INSTALL_PREFIX` and
+ :variable:`CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX`
from relocatable RPM prefix paths.
.. variable:: CPACK_RPM_ADDITIONAL_MAN_DIRS
.. versionadded:: 3.3
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
+ 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.*``
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
@@ -679,21 +727,6 @@ List of CPack RPM generator specific variables:
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
@@ -701,11 +734,11 @@ List of CPack RPM generator specific variables:
default user ownership of RPM content
- * Mandatory : NO
- * Default : root
+ :Mandatory: No
+ :Default: ``root``
Value should be user name and not UID.
- Note that <compName> must be in upper-case.
+ Note that ``<compName>`` must be in upper-case.
.. variable:: CPACK_RPM_DEFAULT_GROUP
CPACK_RPM_<compName>_DEFAULT_GROUP
@@ -714,11 +747,11 @@ List of CPack RPM generator specific variables:
default group ownership of RPM content
- * Mandatory : NO
- * Default : root
+ :Mandatory: No
+ :Default: root
Value should be group name and not GID.
- Note that <compName> must be in upper-case.
+ Note that ``<compName>`` must be in upper-case.
.. variable:: CPACK_RPM_DEFAULT_FILE_PERMISSIONS
CPACK_RPM_<compName>_DEFAULT_FILE_PERMISSIONS
@@ -727,23 +760,23 @@ List of CPack RPM generator specific variables:
default permissions used for packaged files
- * Mandatory : NO
- * Default : - (system default)
+ :Mandatory: No
+ :Default: (system default)
- Accepted values are lists with ``PERMISSIONS``. Valid permissions
+ 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
+ - ``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.
+ Note that ``<compName>`` must be in upper-case.
.. variable:: CPACK_RPM_DEFAULT_DIR_PERMISSIONS
CPACK_RPM_<compName>_DEFAULT_DIR_PERMISSIONS
@@ -752,12 +785,12 @@ List of CPack RPM generator specific variables:
default permissions used for packaged directories
- * Mandatory : NO
- * Default : - (system default)
+ :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.
+ Note that ``<compName>`` must be in upper-case.
.. variable:: CPACK_RPM_INSTALL_WITH_EXEC
@@ -765,8 +798,8 @@ List of CPack RPM generator specific variables:
force execute permissions on programs and shared libraries
- * Mandatory : NO
- * Default : - (system default)
+ :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
@@ -782,7 +815,9 @@ Packaging of Symbolic Links
.. versionadded:: 3.3
-The CPack RPM generator supports packaging of symbolic links::
+The CPack RPM generator supports packaging of symbolic links:
+
+.. code-block:: cmake
execute_process(COMMAND ${CMAKE_COMMAND}
-E create_symlink <relative_path_location> <symlink_name>)
@@ -832,8 +867,8 @@ Debuginfo RPM packaging has its own set of variables:
Enable generation of debuginfo RPM package(s).
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
.. note::
@@ -855,8 +890,8 @@ Debuginfo RPM packaging has its own set of variables:
Provides locations of root directories of source files from which binaries
were built.
- * Mandatory : YES if :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` is set
- * Default : -
+ :Mandatory: Yes if :variable:`CPACK_RPM_DEBUGINFO_PACKAGE` is set
+ :Default:
.. note::
@@ -873,15 +908,15 @@ Debuginfo RPM packaging has its own set of variables:
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>"
+ :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>``
+ 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
@@ -892,8 +927,12 @@ Debuginfo RPM packaging has its own set of variables:
Directories containing sources that should be excluded from debuginfo packages.
- * Mandatory : NO
- * Default : "/usr /usr/src /usr/src/debug"
+ :Mandatory: No
+ :Default:
+ The following paths are excluded by 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.
@@ -903,8 +942,8 @@ Debuginfo RPM packaging has its own set of variables:
Paths that should be appended to :variable:`CPACK_RPM_DEBUGINFO_EXCLUDE_DIRS`
for exclusion.
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
.. variable:: CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE
@@ -912,8 +951,8 @@ Debuginfo RPM packaging has its own set of variables:
Create a single debuginfo package even if components packaging is set.
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
When this variable is enabled it produces a single debuginfo package even if
component packaging is enabled.
@@ -935,8 +974,8 @@ Debuginfo RPM packaging has its own set of variables:
Debuginfo package file name.
- * Mandatory : NO
- * Default : rpmbuild tool generated 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.
@@ -1003,8 +1042,8 @@ Source RPM packaging has its own set of variables:
Should the content be packaged as a source rpm (default is binary rpm).
- * Mandatory : NO
- * Default : OFF
+ :Mandatory: No
+ :Default: ``OFF``
.. note::
@@ -1016,27 +1055,29 @@ Source RPM packaging has its own set of variables:
Additional command-line parameters provided to :manual:`cmake(1)` executable.
- * Mandatory : NO
- * Default : -
+ :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 : "/"
+ :Mandatory: Yes
+ :Default: ``/``
.. variable:: CPACK_RPM_BUILDREQUIRES
List of source rpm build dependencies.
- * Mandatory : NO
- * Default : -
+ :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::
+ example:
+
+ .. code-block:: cmake
set(CPACK_RPM_BUILDREQUIRES "python >= 2.5.0, cmake >= 2.8")
@@ -1044,11 +1085,13 @@ Source RPM packaging has its own set of variables:
.. versionadded:: 3.22
- * Mandatory : NO
- * Default : -
+ :Mandatory: No
+ :Default:
May be used to keep the dependency generator from scanning specific files
or directories for dependencies. Note that you can use a regular
- expression that matches all of the directories or files, for example::
+ expression that matches all of the directories or files, for example:
+
+ .. code-block:: cmake
set(CPACK_RPM_REQUIRES_EXCLUDE_FROM "bin/libqsqloci.*\\.so.*")
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
index 03eb076..c97d542 100644
--- a/Help/dev/experimental.rst
+++ b/Help/dev/experimental.rst
@@ -18,12 +18,37 @@ C++20 Module APIs
=================
Variable: ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
-Value: ``3c375311-a3c9-4396-a187-3227ef642046``
+Value: ``2182bf5c-ef0d-489a-91da-49dbc3090d2a``
In order to support C++20 modules, there are a number of behaviors that have
CMake APIs to provide the required features to build and export them from a
project.
+Limitations
+-----------
+
+There are a number of known limitations of the current C++20 module support in
+CMake. This does not document known limitations or bugs in compilers as these
+can change over time.
+
+For all generators:
+
+- Only in-project modules may be used. While there is some support for
+ exporting module information, there is no mechanism for using it at the
+ moment.
+
+For the Ninja Generators:
+
+- ``ninja`` 1.10 or newer is required.
+
+For the Visual Studio Generators:
+
+- Only Visual Studio 2022 and toolchains newer than 19.34 (Visual Studio
+ 17.4).
+- No support for exporting or installing BMI or module information.
+- No diagnosis of using modules provided by ``PRIVATE`` sources from
+ ``PUBLIC`` module sources.
+
C++20 Module Dependencies
=========================
@@ -77,9 +102,9 @@ For compilers that generate module maps, tell CMake as follows:
set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
"${compiler_flags_for_module_map} -fmodule-mapper=<MODULE_MAP_FILE>")
-Currently, the only supported formats are ``gcc`` and ``msvc``. The ``gcc``
-format is described in the GCC documentation, but the relevant section for the
-purposes of CMake is:
+Currently, the only supported formats are, ``clang``, ``gcc``, and ``msvc``.
+The ``gcc`` 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
@@ -94,6 +119,9 @@ The ``msvc`` format is a response file containing flags required to compile
any module interfaces properly as well as find any required files to satisfy
``import`` statements as required for Microsoft's Visual Studio toolchains.
+Similarly, the ``clang`` format is a response file containing flags using
+Clang's module flags.
+
.. _`D1483r1`: https://mathstuf.fedorapeople.org/fortran-modules/fortran-modules.html
.. _`P1689r5`: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html
.. _`cxx-modules-sandbox`: https://github.com/mathstuf/cxx-modules-sandbox
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index 53be91f..de19aa8 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -345,6 +345,7 @@ policies added for that version. Commit with a message such as::
Update the ``cmake_minimum_required`` version range in CMake itself:
* ``CMakeLists.txt``
+* ``Source/Checks/Curses/CMakeLists.txt``
* ``Utilities/Doxygen/CMakeLists.txt``
* ``Utilities/Sphinx/CMakeLists.txt``
diff --git a/Help/dev/source.rst b/Help/dev/source.rst
index f488b3e..68ca743 100644
--- a/Help/dev/source.rst
+++ b/Help/dev/source.rst
@@ -9,7 +9,7 @@ See documentation on `CMake Development`_ for more information.
C++ Code Style
==============
-We use `clang-format`_ version **6.0** to define our style for C++ code in
+We use `clang-format`_ version **15** 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
diff --git a/Help/envvar/ASM_DIALECT.rst b/Help/envvar/ASM_DIALECT.rst
index c89515e..11dbe5a 100644
--- a/Help/envvar/ASM_DIALECT.rst
+++ b/Help/envvar/ASM_DIALECT.rst
@@ -4,8 +4,14 @@ 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).
+files. ``ASM<DIALECT>`` can be one of:
+
+* ``ASM``
+* ``ASM_NASM`` (Netwide Assembler)
+* ``ASM_MASM`` (Microsoft Assembler)
+* ``ASM_MARMASM`` (Microsoft ARM Assembler)
+* ``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
diff --git a/Help/envvar/ASM_DIALECTFLAGS.rst b/Help/envvar/ASM_DIALECTFLAGS.rst
index 2af4b58..f13efbb 100644
--- a/Help/envvar/ASM_DIALECTFLAGS.rst
+++ b/Help/envvar/ASM_DIALECTFLAGS.rst
@@ -9,6 +9,7 @@ of an assembly language. ``ASM<DIALECT>FLAGS`` can be one of:
* ``ASMFLAGS``
* ``ASM_NASMFLAGS``
* ``ASM_MASMFLAGS``
+* ``ASM_MARMASMFLAGS``
* ``ASM-ATTFLAGS``
.. |CMAKE_LANG_FLAGS| replace:: :variable:`CMAKE_ASM<DIALECT>_FLAGS <CMAKE_<LANG>_FLAGS>`
diff --git a/Help/envvar/CTEST_NO_TESTS_ACTION.rst b/Help/envvar/CTEST_NO_TESTS_ACTION.rst
new file mode 100644
index 0000000..2bc86dc
--- /dev/null
+++ b/Help/envvar/CTEST_NO_TESTS_ACTION.rst
@@ -0,0 +1,14 @@
+CTEST_NO_TESTS_ACTION
+---------------------
+
+.. versionadded:: 3.26
+
+.. include:: ENV_VAR.txt
+
+Environment variable that controls how :manual:`ctest <ctest(1)>` handles
+cases when there are no tests to run. Possible values are: ``error``,
+``ignore``, empty or unset.
+
+The :option:`--no-tests=\<action\> <ctest --no-tests>` option to
+:manual:`ctest <ctest(1)>` overrides this environment variable if both
+are given.
diff --git a/Help/envvar/PackageName_ROOT.rst b/Help/envvar/PackageName_ROOT.rst
index 0cdd384..fa8c385 100644
--- a/Help/envvar/PackageName_ROOT.rst
+++ b/Help/envvar/PackageName_ROOT.rst
@@ -7,10 +7,10 @@
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`.
+``<PackageName>`` is the (case-preserved) 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
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index 2cf823a..f50bb55 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -106,14 +106,14 @@ 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
+(e.g. by using the :genex:`$<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:...>``
+be overridden with the :genex:`$<OUTPUT_CONFIG:...>` and :genex:`$<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:...>``
+in the command config, even if it is wrapped in :genex:`$<OUTPUT_CONFIG:...>`
(because its plain name is not a generator expression).
As an example, consider the following:
@@ -122,8 +122,15 @@ As an example, consider the following:
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>>"
+ 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
@@ -144,18 +151,23 @@ the ``build-Release.ninja`` file) unless they have no ``BYPRODUCTS`` or their
add_custom_command(
TARGET exe
POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E echo "Running no-byproduct command"
+ 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>"
+ 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>"
+ COMMAND
+ ${CMAKE_COMMAND} -E echo
+ "Running common-byproduct command for $<CONFIG>"
BYPRODUCTS exe.txt
)
diff --git a/Help/generator/Xcode.rst b/Help/generator/Xcode.rst
index 9dd5015..ab369d5 100644
--- a/Help/generator/Xcode.rst
+++ b/Help/generator/Xcode.rst
@@ -41,7 +41,7 @@ Swift Support
.. versionadded:: 3.4
-When using the :generator:`Xcode` generator with Xcode 6.1 or higher,
+When using the ``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/importing-exporting/index.rst b/Help/guide/importing-exporting/index.rst
index dd3efb8..51a09c0 100644
--- a/Help/guide/importing-exporting/index.rst
+++ b/Help/guide/importing-exporting/index.rst
@@ -563,8 +563,7 @@ include directories should be specified as relative paths to the
$<INSTALL_INTERFACE:include/TgtName>
)
-The ``$<INSTALL_PREFIX>``
-:manual:`generator expression <cmake-generator-expressions(7)>` may be used as
+The :genex:`$<INSTALL_PREFIX>` generator expression 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:
diff --git a/Help/guide/tutorial/Adding Export Configuration.rst b/Help/guide/tutorial/Adding Export Configuration.rst
index eb14f42..6c83276 100644
--- a/Help/guide/tutorial/Adding Export Configuration.rst
+++ b/Help/guide/tutorial/Adding Export Configuration.rst
@@ -102,7 +102,7 @@ but prepended with a ``PACKAGE_`` prefix.
:end-before: # generate the version file
The :command:`write_basic_package_version_file` is next. This command writes
-a file which is used by the "find_package" document the version and
+a file which is used by :command:`find_package`, documenting the version and
compatibility of the desired package. Here, we use the ``Tutorial_VERSION_*``
variables and say that it is compatible with ``AnyNewerVersion``, which
denotes that this version or any higher one are compatible with the requested
@@ -133,8 +133,8 @@ the following to the bottom of the top level ``CMakeLists.txt``:
:caption: CMakeLists.txt
:name: CMakeLists.txt-export
:language: cmake
- :start-after: # needs to be after the install(TARGETS ) command
+ :start-after: # needs to be after the install(TARGETS) command
-With this export call we now generate a ``Targets.cmake``, allowing the
+With this export call we now generate a ``MathFunctionsTargets.cmake``, allowing the
configured ``MathFunctionsConfig.cmake`` in the build directory to be used by
other projects, without needing it to be installed.
diff --git a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
index 45d5976..787e777 100644
--- a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
+++ b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
@@ -4,33 +4,40 @@ Step 6: Adding Support for a Testing Dashboard
Adding support for submitting our test results to a dashboard is simple. We
already defined a number of tests for our project in
:ref:`Testing Support <Tutorial Testing Support>`. Now we just have to run
-those tests and submit them to a dashboard. To include support for dashboards
-we include the :module:`CTest` module in our top-level ``CMakeLists.txt``.
+those tests and submit them to CDash.
-Replace:
-.. literalinclude:: Step6/CMakeLists.txt
- :caption: CMakeLists.txt
- :name: CMakeLists.txt-enable_testing-remove
- :language: cmake
- :start-after: # enable testing
- :end-before: # does the application run
+Exercise 1 - Send Results to a Testing Dashboard
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-With:
+Goal
+----
-.. literalinclude:: Step7/CMakeLists.txt
- :caption: CMakeLists.txt
- :name: CMakeLists.txt-include-CTest
- :language: cmake
- :start-after: # enable testing
- :end-before: # does the application run
+Display our CTest results with CDash.
+
+Helpful Resources
+-----------------
+
+* :manual:`ctest(1)`
+* :command:`include`
+* :module:`CTest`
+
+Files to Edit
+-------------
-The :module:`CTest` module will automatically call ``enable_testing()``, so we
-can remove it from our CMake files.
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+For this exercise, complete ``TODO 1`` in the top-level ``CMakeLists.txt`` by
+including the :module:`CTest` module. This will enable testing with CTest as
+well as dashboard submissions to CDash, so we can safely remove the call to
+:command:`enable_testing`.
We will also need to acquire a ``CTestConfig.cmake`` file to be placed in the
-top-level directory where we can specify information to CTest about the
-project. It contains:
+top-level directory. When run, the :manual:`ctest <ctest(1)>` executable will
+read this file to gather information about the testing dashboard. It contains:
* The project name
@@ -41,9 +48,10 @@ project. It contains:
* The URL of the CDash instance where the submission's generated documents
will be sent
-One has been provided for you in this directory. It would normally be
-downloaded from the ``Settings`` page of the project on the CDash
-instance that will host and display the test results. Once downloaded from
+For this tutorial, a public dashboard server is used and its corresponding
+``CTestConfig.cmake`` file is provided for you in this step's root directory.
+In practice, this file would be downloaded from a project's ``Settings`` page
+on the CDash instance intended to host the test results. Once downloaded from
CDash, the file should not be modified locally.
.. literalinclude:: Step7/CTestConfig.cmake
@@ -51,11 +59,16 @@ CDash, the file should not be modified locally.
:name: CTestConfig.cmake
:language: cmake
-The :manual:`ctest <ctest(1)>` executable will read in this file when it runs.
-To create a simple dashboard you can run the :manual:`cmake <cmake(1)>`
-executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project,
-but do not build it yet. Instead, change directory to the binary tree, and then
-run:
+
+Build and Run
+-------------
+
+Note that as part of the CDash submission some information about your
+development system (e.g. site name or full pathnames) may displayed publicly.
+
+To create a simple test dashboard, run the :manual:`cmake <cmake(1)>`
+executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
+but do not build it yet. Instead, navigate to the build directory and run:
.. code-block:: console
@@ -70,6 +83,28 @@ type must be specified:
Or, from an IDE, build the ``Experimental`` target.
-The :manual:`ctest <ctest(1)>` executable will build and test the project and
-submit the results to Kitware's public dashboard:
+The :manual:`ctest <ctest(1)>` executable will build the project, run any
+tests, and submit the results to Kitware's public dashboard:
https://my.cdash.org/index.php?project=CMakeTutorial.
+
+Solution
+--------
+
+The only CMake code changed needed in this step was to enable dashboard
+submissions to CDash by including the :module:`CTest` module in our top-level
+``CMakeLists.txt``:
+
+.. raw:: html
+
+ <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/CMakeLists.txt
+ :caption: TODO 1: CMakeLists.txt
+ :name: CMakeLists.txt-include-CTest
+ :language: cmake
+ :start-after: # enable testing
+ :end-before: # does the application run
+
+.. raw:: html
+
+ </details>
diff --git a/Help/guide/tutorial/Adding System Introspection.rst b/Help/guide/tutorial/Adding System Introspection.rst
index ba91df4..b69abd2 100644
--- a/Help/guide/tutorial/Adding System Introspection.rst
+++ b/Help/guide/tutorial/Adding System Introspection.rst
@@ -7,53 +7,156 @@ depends on whether or not the target platform has the ``log`` and ``exp``
functions. Of course almost every platform has these functions but for this
tutorial assume that they are not common.
-If the platform has ``log`` and ``exp`` then we will use them to compute the
-square root in the ``mysqrt`` function. We first test for the availability of
-these functions using the :module:`CheckCXXSourceCompiles` module in
+Exercise 1 - Assessing Dependency Availability
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Goal
+----
+
+Change implementation based on available system dependencies.
+
+Helpful Resources
+-----------------
+
+* :module:`CheckCXXSourceCompiles`
+* :command:`target_compile_definitions`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/mysqrt.cxx``
+
+Getting Started
+---------------
+
+The starting source code is provided in the ``Step7`` directory. In this
+exercise, complete ``TODO 1`` through ``TODO 5``.
+
+Start by editing ``MathFunctions/CMakeLists.txt``. Include the
+:module:`CheckCXXSourceCompiles` module. Then, use
+``check_cxx_source_compiles`` to determine whether ``log`` and ``exp`` are
+available from ``cmath``. If they are available, use
+:command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP``
+as compile definitions.
+
+In the ``MathFunctions/mysqrt.cxx``, include ``cmath``. Then, if the system has
+``log`` and ``exp``, use them to compute the square root.
+
+Build and Run
+-------------
+
+Make a new directory called ``Step7_build``. Run the
+:manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool and run the ``Tutorial`` executable.
+
+This can look like the following:
+
+.. code-block:: console
+
+ mkdir Step7_build
+ cd Step7_build
+ cmake ../Step7
+ cmake --build .
+
+Which function gives better results now, ``sqrt`` or ``mysqrt``?
+
+Solution
+--------
+
+In this exercise we will use functions from the
+:module:`CheckCXXSourceCompiles` module so first we must include it in
``MathFunctions/CMakeLists.txt``.
-Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``,
-after the call to :command:`target_include_directories`:
+.. raw:: html
+
+ <details><summary>TODO 1: Click to show/hide answer</summary>
.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
- :caption: MathFunctions/CMakeLists.txt
+ :caption: TODO 1: MathFunctions/CMakeLists.txt
+ :name: MathFunctions/CMakeLists.txt-include-check_cxx_source_compiles
+ :language: cmake
+ :start-after: # does this system provide the log and exp functions?
+ :end-before: check_cxx_source_compiles
+
+.. raw:: html
+
+ </details>
+
+Then test for the availability of
+``log`` and ``exp`` using ``check_cxx_compiles_source``. This function
+lets us try compiling simple code with the required dependency prior to
+the true source code compilation. The resulting variables ``HAVE_LOG``
+and ``HAVE_EXP`` represent whether those dependencies are available.
+
+.. raw:: html
+
+ <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
+ :caption: TODO 2: MathFunctions/CMakeLists.txt
:name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles
:language: cmake
- :start-after: # to find MathFunctions.h, while we don't.
+ :start-after: include(CheckCXXSourceCompiles)
:end-before: # add compile definitions
-If available, use :command:`target_compile_definitions` to specify
+.. raw:: html
+
+ </details>
+
+Next, we need to pass these CMake variables to our source code. This way,
+our source code can tell what resources are available. If both ``log`` and
+``exp`` are available, use :command:`target_compile_definitions` to specify
``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
+.. raw:: html
+
+ <details><summary>TODO 3: Click to show/hide answer</summary>
+
.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
- :caption: MathFunctions/CMakeLists.txt
+ :caption: TODO 3: MathFunctions/CMakeLists.txt
:name: MathFunctions/CMakeLists.txt-target_compile_definitions
:language: cmake
:start-after: # add compile definitions
:end-before: # install libs
-If ``log`` and ``exp`` are available on the system, then we will use them to
-compute the square root in the ``mysqrt`` function. Add the following code to
-the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the
-``#endif`` before returning the result!):
+.. raw:: html
-.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
- :caption: MathFunctions/mysqrt.cxx
- :name: MathFunctions/mysqrt.cxx-ifdef
- :language: c++
- :start-after: // if we have both log and exp then use them
- :end-before: // do ten iterations
+ </details>
+
+Since we may be using ``log`` and ``exp``, we need to modify
+``mysqrt.cxx`` to include ``cmath``.
+
+.. raw:: html
-We will also need to modify ``mysqrt.cxx`` to include ``cmath``.
+ <details><summary>TODO 4: Click to show/hide answer</summary>
.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
- :caption: MathFunctions/mysqrt.cxx
+ :caption: TODO 4: MathFunctions/mysqrt.cxx
:name: MathFunctions/mysqrt.cxx-include-cmath
:language: c++
:end-before: #include <iostream>
-Run the :manual:`cmake <cmake(1)>` executable or the
-:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
-with your chosen build tool and run the Tutorial executable.
+.. raw:: html
-Which function gives better results now, ``sqrt`` or ``mysqrt``?
+ </details>
+
+If ``log`` and ``exp`` are available on the system, then use them to
+compute the square root in the ``mysqrt`` function. The ``mysqrt`` function in
+``MathFunctions/mysqrt.cxx`` will look as follows:
+
+.. raw:: html
+
+ <details><summary>TODO 5: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
+ :caption: TODO 5: MathFunctions/mysqrt.cxx
+ :name: MathFunctions/mysqrt.cxx-ifdef
+ :language: c++
+ :start-after: // if we have both log and exp then use them
+ :end-before: // do ten iterations
+
+.. raw:: html
+
+ </details>
diff --git a/Help/guide/tutorial/Installing and Testing.rst b/Help/guide/tutorial/Installing and Testing.rst
index fa13040..7a59fcb 100644
--- a/Help/guide/tutorial/Installing and Testing.rst
+++ b/Help/guide/tutorial/Installing and Testing.rst
@@ -1,8 +1,6 @@
Step 5: Installing and Testing
==============================
-.. _`Tutorial Testing Support`:
-
Exercise 1 - Install Rules
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +143,7 @@ are similar. To the end of the top-level ``CMakeLists.txt`` we add:
:name: TODO 3,4: CMakeLists.txt-install-TARGETS
:language: cmake
:start-after: # add the install targets
- :end-before: # enable testing
+ :end-before: # TODO 1: Replace enable_testing() with include(CTest)
.. raw:: html
@@ -154,6 +152,8 @@ are similar. To the end of the top-level ``CMakeLists.txt`` we add:
That is all that is needed to create a basic local
install of the tutorial.
+.. _`Tutorial Testing Support`:
+
Exercise 2 - Testing Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -195,7 +195,7 @@ Build and Run
-------------
Navigate to the build directory and rebuild the application. Then, run the
-``ctest`` executable: :option:`ctest -N` and :option:`ctest -VV`. For
+:program:`ctest` executable: :option:`ctest -N` and :option:`ctest -VV`. For
multi-config generators (e.g. Visual Studio), the configuration type must be
specified with the :option:`-C \<mode\> <ctest -C>` flag. For example, to run tests in Debug
mode use ``ctest -C Debug -VV`` from the build directory
diff --git a/Help/guide/tutorial/Selecting Static or Shared Libraries.rst b/Help/guide/tutorial/Selecting Static or Shared Libraries.rst
index 1c49c23..7befe1d 100644
--- a/Help/guide/tutorial/Selecting Static or Shared Libraries.rst
+++ b/Help/guide/tutorial/Selecting Static or Shared Libraries.rst
@@ -65,7 +65,7 @@ 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.
+SqrtLibrary to be ``True`` when building shared libraries.
.. literalinclude:: Step11/MathFunctions/CMakeLists.txt
:caption: MathFunctions/CMakeLists.txt
diff --git a/Help/guide/tutorial/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt
index 220ed4b..1d8b5a6 100644
--- a/Help/guide/tutorial/Step12/CMakeLists.txt
+++ b/Help/guide/tutorial/Step12/CMakeLists.txt
@@ -94,7 +94,7 @@ install(EXPORT MathFunctionsTargets
)
include(CMakePackageConfigHelpers)
-# generate the config file that is includes the exports
+# generate the config file that 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"
@@ -116,7 +116,7 @@ install(FILES
)
# generate the export targets for the build tree
-# needs to be after the install(TARGETS ) command
+# needs to be after the install(TARGETS) command
export(EXPORT MathFunctionsTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)
diff --git a/Help/guide/tutorial/Step5/CMakeLists.txt b/Help/guide/tutorial/Step5/CMakeLists.txt
index a8f241a..279ddf9 100644
--- a/Help/guide/tutorial/Step5/CMakeLists.txt
+++ b/Help/guide/tutorial/Step5/CMakeLists.txt
@@ -42,7 +42,7 @@ target_include_directories(Tutorial PUBLIC
# TODO 3: Install Tutorial in the bin directory
# Hint: Use the TARGETS and DESTINATION parameters
-# TODO 4: Install Tutorial.h to the include directory
+# TODO 4: Install TutorialConfig.h to the include directory
# Hint: Use the FILES and DESTINATION parameters
# TODO 5: Enable testing
@@ -61,4 +61,4 @@ target_include_directories(Tutorial PUBLIC
# Hint: Use the PASS_REGULAR_EXPRESSION property with "4 is 2"
# TODO 9: Add more tests. Create a function called do_test to avoid copy +
-# paste. Test the following values: 4, 9, 5, 7, 25, -25 and 0.00001.
+# paste. Test the following values: 4, 9, 5, 7, 25, -25 and 0.0001.
diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt
index da9e852..c11e307 100644
--- a/Help/guide/tutorial/Step6/CMakeLists.txt
+++ b/Help/guide/tutorial/Step6/CMakeLists.txt
@@ -45,6 +45,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
+# TODO 1: Replace enable_testing() with include(CTest)
# enable testing
enable_testing()
diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
index b4724c4..e5bdc4d 100644
--- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
@@ -9,6 +9,26 @@ target_include_directories(MathFunctions
# link our compiler flags interface library
target_link_libraries(MathFunctions tutorial_compiler_flags)
+# TODO 1: Include CheckCXXSourceCompiles
+
+# TODO 2: Use check_cxx_source_compiles with simple C++ code to verify
+# availability of:
+# * std::log
+# * std::exp
+# Store the results in HAVE_LOG and HAVE_EXP respectively.
+
+# Hint: Sample C++ code which uses log:
+# #include <cmath>
+# int main() {
+# std::log(1.0);
+# return 0;
+# }
+
+# TODO 3: Conditionally on HAVE_LOG and HAVE_EXP, add private compile
+# definitions "HAVE_LOG" and "HAVE_EXP" to the MathFunctions target.
+
+#Hint: Use target_compile_definitions()
+
# install libs
set(installable_libs MathFunctions tutorial_compiler_flags)
install(TARGETS ${installable_libs} DESTINATION lib)
diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
index abe767d..3d2492a 100644
--- a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
+++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx
@@ -1,5 +1,6 @@
#include <iostream>
+// TODO 4: include cmath
#include "MathFunctions.h"
// a hack square root calculation using simple operations
@@ -9,6 +10,14 @@ double mysqrt(double x)
return 0;
}
+ // TODO 5: If both HAVE_LOG and HAVE_EXP are defined, use the following:
+ //// double result = std::exp(std::log(x) * 0.5);
+ //// std::cout << "Computing sqrt of " << x << " to be " << result
+ //// << " using log and exp" << std::endl;
+ // else, use the existing logic.
+
+ // Hint: Don't forget the #endif before returning the result!
+
double result = x;
// do ten iterations
@@ -20,5 +29,6 @@ double mysqrt(double x)
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
+
return result;
}
diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst
index bb519ad..8b270aa 100644
--- a/Help/guide/using-dependencies/index.rst
+++ b/Help/guide/using-dependencies/index.rst
@@ -277,7 +277,7 @@ for more):
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
- GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
+ GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
)
FetchContent_MakeAvailable(googletest Catch2)
diff --git a/Help/index.rst b/Help/index.rst
index fdbf847..16c8f25 100644
--- a/Help/index.rst
+++ b/Help/index.rst
@@ -57,6 +57,7 @@ Reference Manuals
/manual/cmake-buildsystem.7
/manual/cmake-commands.7
/manual/cmake-compile-features.7
+ /manual/cmake-configure-log.7
/manual/cmake-developer.7
/manual/cmake-env-variables.7
/manual/cmake-file-api.7
diff --git a/Help/manual/ccmake.1.rst b/Help/manual/ccmake.1.rst
index cd66d51..a09857b 100644
--- a/Help/manual/ccmake.1.rst
+++ b/Help/manual/ccmake.1.rst
@@ -13,7 +13,7 @@ Synopsis
Description
===========
-The **ccmake** executable is the CMake curses interface. Project
+The :program:`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.
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index 3c09e86..b9d621b 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -99,7 +99,7 @@ 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
+The ``MACOSX_FRAMEWORK_IDENTIFIER`` sets the ``CFBundleIdentifier`` key
and it uniquely identifies the bundle.
.. code-block:: cmake
@@ -119,7 +119,7 @@ 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
+:genex:`$<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:
@@ -854,7 +854,7 @@ the generator used. For example:
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 the above ``$<CONFIG:Debug>`` expression.
+accounted for by the above :genex:`$<CONFIG:Debug>` expression.
Case Sensitivity
@@ -862,7 +862,7 @@ Case Sensitivity
:variable:`CMAKE_BUILD_TYPE` and :variable:`CMAKE_CONFIGURATION_TYPES` are
just like other variables in that any string comparisons made with their
-values will be case-sensitive. The ``$<CONFIG>`` generator expression also
+values will be case-sensitive. The :genex:`$<CONFIG>` generator expression also
preserves the casing of the configuration as set by the user or CMake defaults.
For example:
@@ -887,7 +887,7 @@ For example:
In contrast, CMake treats the configuration type case-insensitively when
using it internally in places that modify behavior based on the configuration.
-For example, the ``$<CONFIG:Debug>`` generator expression will evaluate to 1
+For example, the :genex:`$<CONFIG:Debug>` generator expression will evaluate to 1
for a configuration of not only ``Debug``, but also ``DEBUG``, ``debug`` or
even ``DeBuG``. Therefore, you can specify configuration types in
:variable:`CMAKE_BUILD_TYPE` and :variable:`CMAKE_CONFIGURATION_TYPES` with
diff --git a/Help/manual/cmake-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst
index 8073511..1e87ec6 100644
--- a/Help/manual/cmake-compile-features.7.rst
+++ b/Help/manual/cmake-compile-features.7.rst
@@ -282,3 +282,25 @@ versions specified for each:
* ``Clang``: Clang compiler 5.0+.
* ``NVIDIA``: NVIDIA nvcc compiler 7.5+.
+
+.. _`Language Standard Flags`:
+
+Language Standard Flags
+=======================
+
+In order to satisfy requirements specified by the
+:command:`target_compile_features` command or the
+:variable:`CMAKE_<LANG>_STANDARD` variable, CMake may pass a
+language standard flag to the compiler, such as ``-std=c++11``.
+
+For :ref:`Visual Studio Generators`, CMake cannot precisely control
+the placement of the language standard flag on the compiler command line.
+For :ref:`Ninja Generators`, :ref:`Makefile Generators`, and
+:generator:`Xcode`, CMake places the language standard flag just after
+the language-wide flags from :variable:`CMAKE_<LANG>_FLAGS`
+and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`.
+
+.. versionchanged:: 3.26
+ The language standard flag is placed before flags specified by other
+ abstractions such as the :command:`target_compile_options` command.
+ Prior to CMake 3.26, the language standard flag was placed after them.
diff --git a/Help/manual/cmake-configure-log.7.rst b/Help/manual/cmake-configure-log.7.rst
new file mode 100644
index 0000000..4d64506
--- /dev/null
+++ b/Help/manual/cmake-configure-log.7.rst
@@ -0,0 +1,334 @@
+.. cmake-manual-description: CMake Configure Log
+
+cmake-configure-log(7)
+**********************
+
+.. versionadded:: 3.26
+
+.. only:: html
+
+ .. contents::
+
+Introduction
+============
+
+CMake writes a running log, known as the *configure log*,
+of certain events that occur during the Configure step.
+The configure log does *not* contain a log of all output, errors,
+or messages printed while configuring a project. It is a log of
+detailed information about specific events, such as toolchain inspection
+by :command:`try_compile`, meant for use in debugging the configuration
+of a build tree.
+
+For human use, this version of CMake writes the configure log to the file::
+
+ ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml
+
+However, the *location and name of the log file may change* in future
+versions of CMake. Tools that read the configure log should get its
+location using a :ref:`configureLog <file-api configureLog>` query to
+the :manual:`cmake-file-api(7)`.
+See the `Log Versioning`_ section below for details.
+
+Log Structure
+=============
+
+The configure log is designed to be both machine- and human-readable.
+
+The log file is a YAML document stream containing zero or more YAML
+documents separated by document markers. Each document begins
+with a ``---`` document marker line, contains a single YAML mapping
+that logs events from one CMake "configure" step, and, if the configure
+step finished normally, ends with a ``...`` document marker line:
+
+.. code-block:: yaml
+
+ ---
+ events:
+ -
+ kind: "try_compile-v1"
+ # (other fields omitted)
+ -
+ kind: "try_compile-v1"
+ # (other fields omitted)
+ ...
+
+A new document is appended to the log every time CMake configures
+the build tree and logs new events.
+
+The keys of the each document root mapping are:
+
+``events``
+ A YAML block sequence of nodes corresponding to events logged during
+ one CMake "configure" step. Each event is a YAML node containing one
+ of the `Event Kinds`_ documented below.
+
+Log Versioning
+--------------
+
+Each of the `Event Kinds`_ is versioned independently. The set of
+keys an event's log entry provides is specific to its major version.
+When an event is logged, the latest version of its event kind that is
+known to the running version of CMake is always written to the log.
+
+Tools reading the configure log must ignore event kinds and versions
+they do not understand:
+
+* A future version of CMake may introduce a new event kind or version.
+
+* If an existing build tree is re-configured with a different version of
+ CMake, the log may contain different versions of the same event kind.
+
+* If :manual:`cmake-file-api(7)` queries request one or more
+ :ref:`configureLog <file-api configureLog>` object versions,
+ the log may contain multiple entries for the same event, each
+ with a different version of its event kind.
+
+IDEs should write a :manual:`cmake-file-api(7)` query requesting a
+specific :ref:`configureLog <file-api configureLog>` object version,
+before running CMake, and then read the configure log only as described
+by the file-api reply.
+
+Text Block Encoding
+-------------------
+
+In order to make the log human-readable, text blocks are always
+represented using YAML literal block scalars (``|``).
+Since literal block scalars do not support escaping, backslashes
+and non-printable characters are encoded at the application layer:
+
+* ``\\`` encodes a backslash.
+* ``\xXX`` encodes a byte using two hexadecimal digits, ``XX``.
+
+.. _`configure-log event kinds`:
+
+Event Kinds
+===========
+
+Every event kind is represented by a YAML mapping of the form:
+
+.. code-block:: yaml
+
+ kind: "<kind>-v<major>"
+ backtrace:
+ - "<file>:<line> (<function>)"
+ checks:
+ - "Checking for something"
+ #...event-specific keys...
+
+The keys common to all events are:
+
+``kind``
+ A string identifying the event kind and major version.
+
+``backtrace``
+ A YAML block sequence reporting the call stack of CMake source
+ locations at which the event occurred, from most-recent to
+ least-recent. Each node is a string specifying one location
+ formatted as ``<file>:<line> (<function>)``.
+
+``checks``
+ An optional key that is present when the event occurred with
+ at least one pending :command:`message(CHECK_START)`. Its value
+ is a YAML block sequence reporting the stack of pending checks,
+ from most-recent to least-recent. Each node is a string containing
+ a pending check message.
+
+Additional mapping keys are specific to each (versioned) event kind,
+described below.
+
+.. _`message configure-log event`:
+
+Event Kind ``message``
+----------------------
+
+The :command:`message(CONFIGURE_LOG)` command logs ``message`` events.
+
+There is only one ``message`` event major version, version 1.
+
+.. _`message-v1 event`:
+
+``message-v1`` Event
+^^^^^^^^^^^^^^^^^^^^
+
+A ``message-v1`` event is a YAML mapping:
+
+.. code-block:: yaml
+
+ kind: "message-v1"
+ backtrace:
+ - "CMakeLists.txt:123 (message)"
+ checks:
+ - "Checking for something"
+ message: |
+ # ...
+
+The keys specific to ``message-v1`` mappings are:
+
+``message``
+ A YAML literal block scalar containing the message text,
+ represented using our `Text Block Encoding`_.
+
+.. _`try_compile configure-log event`:
+
+Event Kind ``try_compile``
+--------------------------
+
+The :command:`try_compile` command logs ``try_compile`` events.
+
+There is only one ``try_compile`` event major version, version 1.
+
+.. _`try_compile-v1 event`:
+
+``try_compile-v1`` Event
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A ``try_compile-v1`` event is a YAML mapping:
+
+.. code-block:: yaml
+
+ kind: "try_compile-v1"
+ backtrace:
+ - "CMakeLists.txt:123 (try_compile)"
+ checks:
+ - "Checking for something"
+ description: "Explicit LOG_DESCRIPTION"
+ directories:
+ source: "/path/to/.../TryCompile-01234"
+ binary: "/path/to/.../TryCompile-01234"
+ cmakeVariables:
+ SOME_VARIABLE: "Some Value"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ exitCode: 0
+
+The keys specific to ``try_compile-v1`` mappings are:
+
+``description``
+ An optional key that is present when the ``LOG_DESCRIPTION <text>`` option
+ was used. Its value is a string containing the description ``<text>``.
+
+``directories``
+ A mapping describing the directories associated with the
+ compilation attempt. It has the following keys:
+
+ ``source``
+ String specifying the source directory of the
+ :command:`try_compile` project.
+
+ ``binary``
+ String specifying the binary directory of the
+ :command:`try_compile` project.
+ For non-project invocations, this is often the same as
+ the source directory.
+
+``cmakeVariables``
+ An optional key that is present when CMake propagates variables
+ into the test project, either automatically or due to the
+ :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable.
+ Its value is a mapping from variable names to their values.
+
+``buildResult``
+ A mapping describing the result of compiling the test code.
+ It has the following keys:
+
+ ``variable``
+ A string specifying the name of the CMake variable
+ storing the result of trying to build the test project.
+
+ ``cached``
+ A boolean indicating whether the above result ``variable``
+ is stored in the CMake cache.
+
+ ``stdout``
+ A YAML literal block scalar containing the output from building
+ the test project, represented using our `Text Block Encoding`_.
+ This contains build output from both stdout and stderr.
+
+ ``exitCode``
+ An integer specifying the build tool exit code from trying
+ to build the test project.
+
+.. _`try_run configure-log event`:
+
+Event Kind ``try_run``
+----------------------
+
+The :command:`try_run` command logs ``try_run`` events.
+
+There is only one ``try_run`` event major version, version 1.
+
+.. _`try_run-v1 event`:
+
+``try_run-v1`` Event
+^^^^^^^^^^^^^^^^^^^^
+
+A ``try_run-v1`` event is a YAML mapping:
+
+.. code-block:: yaml
+
+ kind: "try_run-v1"
+ backtrace:
+ - "CMakeLists.txt:456 (try_run)"
+ checks:
+ - "Checking for something"
+ description: "Explicit LOG_DESCRIPTION"
+ directories:
+ source: "/path/to/.../TryCompile-56789"
+ binary: "/path/to/.../TryCompile-56789"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: |
+ # ...
+ stderr: |
+ # ...
+ exitCode: 0
+
+The keys specific to ``try_run-v1`` mappings include those
+documented by the `try_compile-v1 event`_, plus:
+
+``runResult``
+ A mapping describing the result of running the test code.
+ It has the following keys:
+
+ ``variable``
+ A string specifying the name of the CMake variable
+ storing the result of trying to run the test executable.
+
+ ``cached``
+ A boolean indicating whether the above result ``variable``
+ is stored in the CMake cache.
+
+ ``stdout``
+ An optional key that is present when the test project built successfully.
+ Its value is a YAML literal block scalar containing output from running
+ the test executable, represented using our `Text Block Encoding`_.
+
+ If ``RUN_OUTPUT_VARIABLE`` was used, stdout and stderr are captured
+ together, so this will contain both. Otherwise, this will contain
+ only the stdout output.
+
+ ``stderr``
+ An optional key that is present when the test project built successfully
+ and the ``RUN_OUTPUT_VARIABLE`` option was not used.
+ Its value is a YAML literal block scalar containing output from running
+ the test executable, represented using our `Text Block Encoding`_.
+
+ If ``RUN_OUTPUT_VARIABLE`` was used, stdout and stderr are captured
+ together in the ``stdout`` key, and this key will not be present.
+ Otherwise, this will contain the stderr output.
+
+ ``exitCode``
+ An optional key that is present when the test project built successfully.
+ Its value is an integer specifying the exit code, or a string containing
+ an error message, from trying to run the test executable.
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
index 0f3c30a..a09bd14 100644
--- a/Help/manual/cmake-developer.7.rst
+++ b/Help/manual/cmake-developer.7.rst
@@ -560,7 +560,7 @@ 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
+Most of the cache variables should be hidden in the :program:`ccmake` interface unless
the user explicitly asks to edit them.
.. code-block:: cmake
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index 50fcf75..4c29b80 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -92,6 +92,7 @@ Environment Variables for CTest
/envvar/CMAKE_CONFIG_TYPE
/envvar/CTEST_INTERACTIVE_DEBUG_MODE
+ /envvar/CTEST_NO_TESTS_ACTION
/envvar/CTEST_OUTPUT_ON_FAILURE
/envvar/CTEST_PARALLEL_LEVEL
/envvar/CTEST_PROGRESS_OUTPUT
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 4b8ac65..7ff9728 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -258,8 +258,8 @@ The members are:
``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,
+ It has members for :program:`cmake`, :program:`ctest`, and :program:`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`).
@@ -371,7 +371,7 @@ 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.
+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
@@ -425,7 +425,7 @@ Version 1 does not exist to avoid confusion with that from
{
"kind": "codemodel",
- "version": { "major": 2, "minor": 4 },
+ "version": { "major": 2, "minor": 5 },
"paths": {
"source": "/path/to/top-level-source-dir",
"build": "/path/to/top-level-build-dir"
@@ -1071,6 +1071,27 @@ with members:
available. The value is an unsigned integer 0-based index into
the ``backtraceGraph`` member's ``nodes`` array.
+``fileSets``
+ A JSON array of entries corresponding to the target's file sets. Each entry
+ is a JSON object with members:
+
+ ``name``
+ A string specifying the name of the file set.
+
+ ``type``
+ A string specifying the type of the file set. See
+ :command:`target_sources` supported file set types.
+
+ ``visibility``
+ A string specifying the visibility of the file set; one of ``PUBLIC``,
+ ``PRIVATE``, or ``INTERFACE``.
+
+ ``baseDirectories``
+ A JSON array of strings specifying the base directories containing sources
+ in the file set.
+
+ This field was added in codemodel version 2.5.
+
``sources``
A JSON array of entries corresponding to the target's source files.
Each entry is a JSON object with members:
@@ -1096,6 +1117,13 @@ with members:
Optional member that is present with boolean value ``true`` if
the source is :prop_sf:`GENERATED`.
+ ``fileSetIndex``
+ Optional member that is present when the source is part of a file set.
+ The value is an unsigned integer 0-based index into the ``fileSets``
+ array.
+
+ This field was added in codemodel version 2.5.
+
``backtrace``
Optional member that is present when a CMake language backtrace to
the :command:`target_sources`, :command:`add_executable`,
@@ -1270,6 +1298,45 @@ elsewhere in the containing object. The backtrace graph object members are:
directory then the path is specified relative to that directory.
Otherwise the path is absolute.
+.. _`file-api configureLog`:
+
+Object Kind "configureLog"
+--------------------------
+
+The ``configureLog`` object kind describes the location and contents of
+a :manual:`cmake-configure-log(7)` file.
+
+There is only one ``configureLog`` object major version, version 1.
+
+"configureLog" version 1
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+``configureLog`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+ {
+ "kind": "configureLog",
+ "version": { "major": 1, "minor": 0 },
+ "path": "/path/to/top-level-build-dir/CMakeFiles/CMakeConfigureLog.yaml",
+ "eventKindNames": [ "try_compile-v1", "try_run-v1" ]
+ }
+
+The members specific to ``configureLog`` objects are:
+
+``path``
+ A string specifying the path to the configure log file.
+ Clients must read the log file from this path, which may be
+ different than the path documented by :manual:`cmake-configure-log(7)`.
+ The log file may not exist if no events are logged.
+
+``eventKindNames``
+ A JSON array whose entries are each a JSON string naming one
+ of the :manual:`cmake-configure-log(7)` versioned event kinds.
+ At most one version of each configure log event kind will be listed.
+ Although the configure log may contain other (versioned) event kinds,
+ clients must ignore those that are not listed in this field.
+
Object Kind "cache"
-------------------
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 69e3f20..c3e87d7 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -142,9 +142,9 @@ to generate debug messages is to add a custom target:
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$<...>")
-After running ``cmake``, you can then build the ``genexdebug`` target to print
+After running :program:`cmake`, you can then build the ``genexdebug`` target to print
the result of the ``$<...>`` expression (i.e. run the command
-``cmake --build ... --target genexdebug``).
+:option:`cmake --build ... --target genexdebug <cmake--build --target>`).
Another way is to write debug messages to a file with :command:`file(GENERATE)`:
@@ -1401,6 +1401,13 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
Note that ``tgt`` is not added as a dependency of the target this
expression is evaluated on.
+ .. versionchanged:: 3.26
+ When encountered during evaluation of :ref:`Target Usage Requirements`,
+ typically in an ``INTERFACE_*`` target property, lookup of the ``tgt``
+ name occurs in the directory of the target specifying the requirement,
+ rather than the directory of the consuming target for which the
+ expression is being evaluated.
+
.. genex:: $<TARGET_PROPERTY:prop>
Value of the property ``prop`` on the target for which the expression
@@ -1666,8 +1673,8 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
**On non-DLL platforms, this expression always 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:
+ depends on into its output directory in a ``POST_BUILD`` custom command using
+ the :option:`cmake -E copy -t <cmake-E copy>` command. For example:
.. code-block:: cmake
@@ -1676,7 +1683,7 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
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 ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:exe> $<TARGET_RUNTIME_DLLS:exe>
COMMAND_EXPAND_LISTS
)
@@ -1689,6 +1696,9 @@ In the following, the phrase "the ``tgt`` filename" means the name of the
section for details. Many :ref:`Find Modules` produce imported targets
with the ``UNKNOWN`` type and therefore will be ignored.
+On platforms that support runtime paths (``RPATH``), refer to the
+:prop_tgt:`INSTALL_RPATH` target property.
+On Apple platforms, refer to the :prop_tgt:`INSTALL_NAME_DIR` target property.
Export And Install Expressions
------------------------------
@@ -1704,6 +1714,13 @@ Export And Install Expressions
when the target is used by another target in the same buildsystem. Expands to
the empty string otherwise.
+.. genex:: $<BUILD_LOCAL_INTERFACE:...>
+
+ .. versionadded:: 3.26
+
+ Content of ``...`` when the target is used by another target in the same
+ buildsystem. Expands to the empty string otherwise.
+
.. genex:: $<INSTALL_PREFIX>
Content of the install prefix when the target is exported via
diff --git a/Help/manual/cmake-gui.1.rst b/Help/manual/cmake-gui.1.rst
index dd0eeca..cdb860f 100644
--- a/Help/manual/cmake-gui.1.rst
+++ b/Help/manual/cmake-gui.1.rst
@@ -16,7 +16,7 @@ Synopsis
Description
===========
-The **cmake-gui** executable is the CMake GUI. Project configuration
+The :program:`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.
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
index 0bd561f..d0774cb 100644
--- a/Help/manual/cmake-language.7.rst
+++ b/Help/manual/cmake-language.7.rst
@@ -37,10 +37,10 @@ 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.
+with the :option:`-P <cmake -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
-------
@@ -206,7 +206,7 @@ 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
+.. ATTENTION No code-block syntax highlighting in the following example
(long string literal not supported by our cmake.py)
For example::
@@ -254,7 +254,7 @@ 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
+.. ATTENTION No code-block syntax highlighting in the following example
(escape \" not supported by our cmake.py)
For example:
@@ -268,7 +268,7 @@ For example:
It does end in an unescaped double quote.
")
-.. No code-block syntax highlighting in the following example
+.. ATTENTION 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
@@ -530,6 +530,9 @@ of alphanumeric characters plus ``_`` and ``-``.
Variables have dynamic scope. Each variable "set" or "unset"
creates a binding in the current scope:
+Block Scope
+ The :command:`block` command may create a new scope for variable bindings.
+
Function Scope
`Command Definitions`_ created by the :command:`function` command
create commands that, when invoked, process the recorded commands
@@ -542,8 +545,8 @@ Directory Scope
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.
+ scope. CMake `Scripts`_, when processed with :option:`cmake -P`,
+ bind variables in one "directory" scope.
A variable "set" or "unset" not inside a function call binds
to the current directory scope.
@@ -597,11 +600,11 @@ Initialization
Changed values are not written back to the calling process,
and they are not seen by subsequent build or test processes.
- See the :ref:`cmake -E env <Run a Command-Line Tool>` command-line
+ See the :option:`cmake -E env <cmake-E env>` command-line
tool to run a command in a modified environment.
Inspection
- See the :ref:`cmake -E environment <Run a Command-Line Tool>` command-line
+ See the :option:`cmake -E environment <cmake-E environment>` command-line
tool to display all current environment variables.
The :manual:`cmake-env-variables(7)` manual documents environment
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d161a28..448d8ba 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -161,7 +161,6 @@ They are normally called through the :command:`find_package` command.
/module/FindICU
/module/FindImageMagick
/module/FindIntl
- /module/FindITK
/module/FindJasper
/module/FindJava
/module/FindJNI
@@ -252,8 +251,6 @@ They are normally called through the :command:`find_package` command.
/module/FindTclStub
/module/FindThreads
/module/FindTIFF
- /module/FindUnixCommands
- /module/FindVTK
/module/FindVulkan
/module/FindWget
/module/FindWish
@@ -296,9 +293,12 @@ Deprecated Find Modules
:maxdepth: 1
/module/FindCUDA
+ /module/FindITK
/module/FindPythonInterp
/module/FindPythonLibs
/module/FindQt
+ /module/FindUnixCommands
+ /module/FindVTK
/module/FindwxWindows
Legacy CPack Modules
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index d6a30ff..22e9eb2 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,13 @@ 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.26
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0143: USE_FOLDERS global property is treated as ON by default. </policy/CMP0143>
Policies Introduced by CMake 3.25
=================================
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index b17be82..fb84f5a 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -77,8 +77,6 @@ Properties on Directories
/prop_dir/IMPORTED_TARGETS
/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
@@ -195,6 +193,7 @@ Properties on Targets
/prop_tgt/CXX_MODULE_SET
/prop_tgt/CXX_MODULE_SET_NAME
/prop_tgt/CXX_MODULE_SETS
+ /prop_tgt/CXX_SCAN_FOR_MODULES
/prop_tgt/CXX_STANDARD
/prop_tgt/CXX_STANDARD_REQUIRED
/prop_tgt/DEBUG_POSTFIX
@@ -300,6 +299,7 @@ Properties on Targets
/prop_tgt/JOB_POOL_PRECOMPILE_HEADER
/prop_tgt/LABELS
/prop_tgt/LANG_CLANG_TIDY
+ /prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR
/prop_tgt/LANG_COMPILER_LAUNCHER
/prop_tgt/LANG_CPPCHECK
/prop_tgt/LANG_CPPLINT
@@ -533,6 +533,7 @@ Properties on Source Files
/prop_sf/COMPILE_DEFINITIONS
/prop_sf/COMPILE_FLAGS
/prop_sf/COMPILE_OPTIONS
+ /prop_sf/CXX_SCAN_FOR_MODULES
/prop_sf/EXTERNAL_OBJECT
/prop_sf/Fortran_FORMAT
/prop_sf/Fortran_PREPROCESS
@@ -618,6 +619,8 @@ Deprecated Properties on Directories
/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES
/prop_dir/COMPILE_DEFINITIONS_CONFIG
+ /prop_dir/INTERPROCEDURAL_OPTIMIZATION
+ /prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG
/prop_dir/TEST_INCLUDE_FILE
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index cd46615..23d8256 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -131,6 +131,7 @@ Variables that Provide Information
/variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
/variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
/variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION
+ /variable/CMAKE_VS_VERSION_BUILD_NUMBER
/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
/variable/CMAKE_XCODE_BUILD_SYSTEM
@@ -417,6 +418,7 @@ Variables that Control the Build
/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
/variable/CMAKE_CUDA_RUNTIME_LIBRARY
/variable/CMAKE_CUDA_SEPARABLE_COMPILATION
+ /variable/CMAKE_CXX_SCAN_FOR_MODULES
/variable/CMAKE_DEBUG_POSTFIX
/variable/CMAKE_DEFAULT_BUILD_TYPE
/variable/CMAKE_DEFAULT_CONFIGS
@@ -449,6 +451,7 @@ Variables that Control the Build
/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG
/variable/CMAKE_IOS_INSTALL_COMBINED
/variable/CMAKE_LANG_CLANG_TIDY
+ /variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR
/variable/CMAKE_LANG_COMPILER_LAUNCHER
/variable/CMAKE_LANG_CPPCHECK
/variable/CMAKE_LANG_CPPLINT
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index b31ad11..e48ecd9 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -39,20 +39,20 @@ Synopsis
Description
===========
-The **cmake** executable is the command-line interface of the cross-platform
+The :program:`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
+Optionally use :program:`cmake` to `Build a Project`_, `Install a Project`_ or just
+run the corresponding build tool (e.g. ``make``) directly. :program:`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**,
+For graphical user interfaces that may be used in place of :program:`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)>`.
@@ -193,7 +193,7 @@ build tool to build the project. For example, after using the
$ make
$ make install
-Alternatively, one may use **cmake** to `Build a Project`_ by
+Alternatively, one may use :program:`cmake` to `Build a Project`_ by
automatically choosing and invoking the appropriate native build tool.
.. _`CMake Options`:
@@ -362,9 +362,8 @@ Options
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
+ :caption: JSON trace format
{
"file": "/full/path/to/the/CMake/file.txt",
@@ -417,9 +416,8 @@ Options
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
+ :caption: JSON version format
{
"version": {
@@ -850,17 +848,21 @@ Available commands are:
.. program:: cmake-E
-.. option:: copy <file>... <destination>
+.. option:: copy <file>... <destination>, copy -t <destination> <file>...
Copy files to ``<destination>`` (either file or directory).
- If multiple files are specified, the ``<destination>`` must be
- directory and it must exist. Wildcards are not supported.
- ``copy`` does follow symlinks. That means it does not copy symlinks,
- but the files or directories it point to.
+ If multiple files are specified, or if ``-t`` is specified, the
+ ``<destination>`` must be directory and it must exist. If ``-t`` is not
+ specified, the last argument is assumed to be the ``<destination>``.
+ Wildcards are not supported. ``copy`` does follow symlinks. That means it
+ does not copy symlinks, but the files or directories it point to.
.. versionadded:: 3.5
Support for multiple input files.
+ .. versionadded:: 3.26
+ Support for ``-t`` argument.
+
.. option:: copy_directory <dir>... <destination>
Copy content of ``<dir>...`` directories to ``<destination>`` directory.
@@ -874,6 +876,16 @@ Available commands are:
The command now fails when the source directory does not exist.
Previously it succeeded by creating an empty destination directory.
+.. option:: copy_directory_if_different <dir>... <destination>
+
+ .. versionadded:: 3.26
+
+ Copy changed content of ``<dir>...`` directories to ``<destination>`` directory.
+ If ``<destination>`` directory does not exist it will be created.
+
+ ``copy_directory_if_different`` does follow symlinks.
+ The command fails when the source directory does not exist.
+
.. option:: copy_if_different <file>... <destination>
Copy files to ``<destination>`` (either file or directory) if
@@ -939,7 +951,7 @@ Available commands are:
The ``NAME=VALUE`` and ``--unset=NAME`` options are equivalent to
``--modify NAME=set:VALUE`` and ``--modify NAME=unset:``, respectively.
Note that ``--modify NAME=reset:`` resets ``NAME`` to the value it had
- when ``cmake`` launched (or unsets it), not to the most recent
+ when :program:`cmake` launched (or unsets it), not to the most recent
``NAME=VALUE`` option.
.. option:: --
@@ -1068,10 +1080,6 @@ Available commands are:
situations instead. Use ``--`` to stop interpreting options and treat all
remaining arguments as paths, even if they start with ``-``.
-.. option:: server
-
- Launch :manual:`cmake-server(7)` mode.
-
.. option:: sleep <number>...
.. versionadded:: 3.0
@@ -1319,7 +1327,7 @@ To view the presets available for a project, use
Return Value (Exit Code)
========================
-Upon regular termination, the ``cmake`` executable returns the exit code ``0``.
+Upon regular termination, the :program:`cmake` executable returns the exit code ``0``.
If termination is caused by the command :command:`message(FATAL_ERROR)`,
or another error condition, then a non-zero exit code is returned.
diff --git a/Help/manual/cpack.1.rst b/Help/manual/cpack.1.rst
index 3f26d72..1a101a4 100644
--- a/Help/manual/cpack.1.rst
+++ b/Help/manual/cpack.1.rst
@@ -13,10 +13,10 @@ Synopsis
Description
===========
-The **cpack** executable is the CMake packaging program. It generates
+The :program:`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,
+For each installer or package format, :program:`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
@@ -28,7 +28,7 @@ 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 :option:`-G <cpack -G>`.
-The **cpack** program is steered by a configuration file written in the
+The :program:`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 :option:`--config <cpack --config>`, the
file ``CPackConfig.cmake`` in the current directory is used.
@@ -45,7 +45,7 @@ Options
.. option:: -G <generators>
``<generators>`` is a :ref:`semicolon-separated list <CMake Language Lists>`
- of generator names. ``cpack`` will iterate through this list and produce
+ of generator names. :program:`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
@@ -58,30 +58,30 @@ Options
: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.
+ :program:`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``.
+ have already been built before invoking :program:`cpack`.
.. option:: -D <var>=<value>
Set a CPack variable. This will override any value set for ``<var>`` in the
- input file read by ``cpack``.
+ input file read by :program:`cpack`.
.. option:: --config <configFile>
- Specify the configuration file read by ``cpack`` to provide the packaging
+ Specify the configuration file read by :program:`cpack` to provide the packaging
details. By default, ``CPackConfig.cmake`` in the current directory will
be used.
.. option:: -V, --verbose
- Run ``cpack`` with verbose output. This can be used to show more details
+ Run :program:`cpack` with verbose output. This can be used to show more details
from the package generation tools and is suitable for project developers.
.. option:: --debug
- Run ``cpack`` with debug output. This option is intended mainly for the
- developers of ``cpack`` itself and is not normally needed by project
+ Run :program:`cpack` with debug output. This option is intended mainly for the
+ developers of :program:`cpack` itself and is not normally needed by project
developers.
.. option:: --trace
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index 3497a9f..5e82faa 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -32,7 +32,7 @@ Synopsis
Description
===========
-The **ctest** executable is the CMake test driver program.
+The :program:`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.
@@ -69,7 +69,7 @@ Run Tests
Enable short progress output from tests.
- When the output of **ctest** is being sent directly to a terminal, the
+ When the output of :program:`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.
@@ -137,7 +137,7 @@ Run Tests
:ref:`resource specification file <ctest-resource-specification-file>`
specified in ``<file>``.
- When ``ctest`` is run as a `Dashboard Client`_ this sets the
+ When :program:`ctest` is run as a `Dashboard Client`_ this sets the
``ResourceSpecFile`` option of the `CTest Test Step`_.
.. option:: --test-load <level>
@@ -146,7 +146,7 @@ Run Tests
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
+ When :program:`ctest` is run as a `Dashboard Client`_ this sets the
``TestLoad`` option of the `CTest Test Step`_.
.. option:: -Q, --quiet
@@ -435,6 +435,11 @@ Run Tests
unifies the behavior of CTest by either returning an error code if no tests
were found or by ignoring it.
+ .. versionadded:: 3.26
+
+ This option can also be set by setting the :envvar:`CTEST_NO_TESTS_ACTION`
+ environment variable.
+
View Help
=========
@@ -473,7 +478,7 @@ with the following labels:
* *test4* has label *wednesday*
* *test5* has labels *friday* and *test*
-Running ``ctest`` with ``-L tuesday -L test`` will select *test2*, which has
+Running :program:`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.
@@ -832,7 +837,7 @@ 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
+Run the :program:`ctest` command with the current working directory set
to the build tree and use one of these signatures::
ctest -D <mode>[<step>]
@@ -865,7 +870,7 @@ 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
+well as performing the testing steps. Run the :program:`ctest` command
with the current working directory set outside of any build tree
and use one of these signatures::
@@ -1142,7 +1147,7 @@ Configuration settings include:
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 :option:`-C <ctest -C>`
- option is given to the ``ctest`` command. The value will be substituted
+ option is given to the :program:`ctest` command. The value will be substituted
into the value of ``MakeCommand`` to replace the literal string
``${CTEST_CONFIGURATION_TYPE}`` if it appears.
@@ -1624,7 +1629,7 @@ resource allocation feature. Tests should check the
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
+even if it exists for the parent :program:`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.
diff --git a/Help/policy/CMP0053.rst b/Help/policy/CMP0053.rst
index 9b18b2d..58500d6 100644
--- a/Help/policy/CMP0053.rst
+++ b/Help/policy/CMP0053.rst
@@ -20,7 +20,7 @@ cleaned up to simplify the behavior. Specifically:
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
+ implementation of ``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.
diff --git a/Help/policy/CMP0101.rst b/Help/policy/CMP0101.rst
index f02bccc..6781079 100644
--- a/Help/policy/CMP0101.rst
+++ b/Help/policy/CMP0101.rst
@@ -3,16 +3,24 @@ CMP0101
.. versionadded:: 3.17
-:command:`target_compile_options` now honors ``BEFORE`` keyword in all scopes.
+:command:`target_compile_options` now always honors the ``BEFORE`` keyword.
-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.
+In CMake 3.16 and below, the :command:`target_compile_options` command
+ignores the ``BEFORE`` keyword when inserting items into the
+:prop_tgt:`COMPILE_OPTIONS` target property (``PRIVATE`` and ``PUBLIC``
+items). CMake 3.17 and later honors the ``BEFORE`` keyword in all cases.
+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.
+The behavior of inserting items into the :prop_tgt:`INTERFACE_COMPILE_OPTIONS`
+target property (``PUBLIC`` and ``INTERFACE`` items) is not affected by this
+policy. The ``BEFORE`` keyword has always been honored when adding items to
+:prop_tgt:`INTERFACE_COMPILE_OPTIONS`.
+
+The ``OLD`` behavior for this policy is to not honor the ``BEFORE`` keyword
+when inserting into the :prop_tgt:`COMPILE_OPTIONS` property.
+The ``NEW`` behavior for this policy is to honor the ``BEFORE`` keyword in
+all cases.
This policy was introduced in CMake version 3.17. Use the
:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
diff --git a/Help/policy/CMP0143.rst b/Help/policy/CMP0143.rst
new file mode 100644
index 0000000..24fdc27
--- /dev/null
+++ b/Help/policy/CMP0143.rst
@@ -0,0 +1,30 @@
+CMP0143
+-------
+
+.. versionadded:: 3.26
+
+:prop_gbl:`USE_FOLDERS` global property is treated as ``ON`` by default.
+
+When using CMake 3.25 or earlier, :prop_gbl:`USE_FOLDERS` is treated
+as ``OFF`` by default unless projects enable the feature. For example:
+
+.. code-block:: cmake
+
+ cmake_minimum_required(VERSION 3.25)
+ project(foobar LANGUAGES CXX)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+CMake 3.26 and later prefer to enable the feature by default.
+
+Note that it is the policy setting at the `end` of the top level
+``CMakeLists.txt`` file that matters. The policy setting applies globally
+to the whole project.
+
+This policy provides compatibility with projects that have not been updated
+to expect enabling of folders. Enabling folders causes projects to appear
+differently in IDEs. The policy was introduced in CMake version 3.26. 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/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
index b6f6160..a19cc4e 100644
--- a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
+++ b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
@@ -10,7 +10,7 @@ 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
+Arguments to ``ADDITIONAL_MAKE_CLEAN_FILES`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.
This property only works for the Makefile generators.
diff --git a/Help/prop_dir/COMPILE_DEFINITIONS.rst b/Help/prop_dir/COMPILE_DEFINITIONS.rst
index 18f4567..5a12c1e 100644
--- a/Help/prop_dir/COMPILE_DEFINITIONS.rst
+++ b/Help/prop_dir/COMPILE_DEFINITIONS.rst
@@ -19,6 +19,9 @@ directory's parent.
CMake will automatically drop some definitions that are not supported
by the native build tool.
+.. versionadded:: 3.26
+ Any leading ``-D`` on an item will be removed.
+
.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions" with
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst
index 0c78dfb..6693a43 100644
--- a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst
@@ -1,7 +1,6 @@
INTERPROCEDURAL_OPTIMIZATION
----------------------------
-Enable interprocedural optimization for targets in a directory.
+This directory property does not exist anymore.
-If set to true, enables interprocedural optimizations if they are
-known to be supported by the compiler.
+See the target property :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` instead.
diff --git a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 840a1db..7ef1bb4 100644
--- a/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -1,8 +1,6 @@
INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
-------------------------------------
-Per-configuration interprocedural optimization for a directory.
+This directory property does not exist anymore.
-This is a per-configuration version of ``INTERPROCEDURAL_OPTIMIZATION``.
-If set, this property overrides the generic property for the named
-configuration.
+See the target property :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>` instead.
diff --git a/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
index 07c732b..600a64a 100644
--- a/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
+++ b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
@@ -9,7 +9,7 @@ Name of the :command:`source_group` for :prop_tgt:`AUTOMOC`,
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
+``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.
diff --git a/Help/prop_gbl/JOB_POOLS.rst b/Help/prop_gbl/JOB_POOLS.rst
index 21da4662..5dfe6de 100644
--- a/Help/prop_gbl/JOB_POOLS.rst
+++ b/Help/prop_gbl/JOB_POOLS.rst
@@ -5,8 +5,8 @@ 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).
+The ``JOB_POOLS`` property is a semicolon-separated list of
+pairs using the syntax ``NAME=integer`` (without a space after the equality sign).
For instance:
@@ -21,7 +21,7 @@ or per target by setting the target properties
: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
+Using a pool that is not defined by ``JOB_POOLS`` causes
an error by ninja at build time.
If not set, this property uses the value of the :variable:`CMAKE_JOB_POOLS`
diff --git a/Help/prop_gbl/USE_FOLDERS.rst b/Help/prop_gbl/USE_FOLDERS.rst
index 5919723..6f5a083 100644
--- a/Help/prop_gbl/USE_FOLDERS.rst
+++ b/Help/prop_gbl/USE_FOLDERS.rst
@@ -1,10 +1,17 @@
USE_FOLDERS
-----------
-Use the :prop_tgt:`FOLDER` target property to organize targets into
-folders.
+Controls whether to use the :prop_tgt:`FOLDER` target property to organize
+targets into folders. The value of ``USE_FOLDERS`` at the end of the top level
+``CMakeLists.txt`` file is what determines the behavior.
-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.
+.. versionchanged:: 3.26
+
+ CMake treats this property as ``ON`` by default.
+ See policy :policy:`CMP0143`.
+
+Not all CMake generators support recording folder details for targets.
+The :generator:`Xcode` and :ref:`Visual Studio <Visual Studio Generators>`
+generators are examples of generators that do. Similarly, not all IDEs
+support presenting targets using folder hierarchies, even if the CMake
+generator used provides the necessary information.
diff --git a/Help/prop_sf/COMPILE_DEFINITIONS.rst b/Help/prop_sf/COMPILE_DEFINITIONS.rst
index 6317690..2af896e 100644
--- a/Help/prop_sf/COMPILE_DEFINITIONS.rst
+++ b/Help/prop_sf/COMPILE_DEFINITIONS.rst
@@ -16,6 +16,9 @@ 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.
+.. versionadded:: 3.26
+ Any leading ``-D`` on an item will be removed.
+
.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
Contents of ``COMPILE_DEFINITIONS`` may use :manual:`cmake-generator-expressions(7)`
diff --git a/Help/prop_sf/CXX_SCAN_FOR_MODULES.rst b/Help/prop_sf/CXX_SCAN_FOR_MODULES.rst
new file mode 100644
index 0000000..23c4859
--- /dev/null
+++ b/Help/prop_sf/CXX_SCAN_FOR_MODULES.rst
@@ -0,0 +1,24 @@
+CXX_SCAN_FOR_MODULES
+--------------------
+
+.. versionadded:: 3.26
+
+``CXX_SCAN_FOR_MODULES`` is a boolean specifying whether CMake will scan the
+source for C++ module dependencies. See also the
+:prop_tgt:`CXX_SCAN_FOR_MODULES` for target-wide settings.
+
+When this property is set ``ON``, CMake will scan the source at build time and
+add module dependency information to the compile line as necessary. When this
+property is set ``OFF``, CMake will not scan the source at build time. When
+this property is unset, the :prop_tgt:`CXX_SCAN_FOR_MODULES` property is
+consulted.
+
+Note that scanning is only performed if C++20 or higher is enabled for the
+target and the source uses the ``CXX`` language. Scanning for modules in
+sources belonging to file sets of type ``CXX_MODULES`` and
+``CXX_MODULES_HEADER_UNITS`` is always performed.
+
+.. note ::
+
+ This setting is meaningful only when experimental support for C++ modules
+ has been enabled by the ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` gate.
diff --git a/Help/prop_sf/SKIP_AUTOUIC.rst b/Help/prop_sf/SKIP_AUTOUIC.rst
index ae9725a..45ed3f8 100644
--- a/Help/prop_sf/SKIP_AUTOUIC.rst
+++ b/Help/prop_sf/SKIP_AUTOUIC.rst
@@ -5,7 +5,7 @@ SKIP_AUTOUIC
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
+``SKIP_AUTOUIC`` can be set on C++ header and source files and on
``.ui`` files.
For broader exclusion control see :prop_sf:`SKIP_AUTOGEN`.
diff --git a/Help/prop_test/LABELS.rst b/Help/prop_test/LABELS.rst
index d827adc..02e2fae 100644
--- a/Help/prop_test/LABELS.rst
+++ b/Help/prop_test/LABELS.rst
@@ -2,7 +2,7 @@ LABELS
------
Specify a list of text labels associated with a test. The labels are
-reported in both the ``ctest`` output summary and in dashboard submissions.
+reported in both the :program:`ctest` output summary and in dashboard submissions.
They can also be used to filter the set of tests to be executed (see the
:option:`ctest -L` and :option:`ctest -LE` options).
diff --git a/Help/prop_test/TIMEOUT_AFTER_MATCH.rst b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
index 726dcab..aa17590 100644
--- a/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
+++ b/Help/prop_test/TIMEOUT_AFTER_MATCH.rst
@@ -28,14 +28,14 @@ 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
+``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
+``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`.
+:prop_test:`RESOURCE_LOCK` instead of ``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_tgt/AUTOGEN_BUILD_DIR.rst b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
index ff42ae8..1ca0969 100644
--- a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
+++ b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst
@@ -13,7 +13,7 @@ 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.
+By default ``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
index 563190a..9350a4f 100644
--- a/Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst
+++ b/Help/prop_tgt/AUTOGEN_ORIGIN_DEPENDS.rst
@@ -11,16 +11,16 @@ Targets which have their :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` property
``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
+``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
+By default ``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`)
+ (enabled by default via ``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
@@ -29,12 +29,12 @@ with Qt.
Note
^^^^
-Disabling :prop_tgt:`AUTOGEN_ORIGIN_DEPENDS` is useful to avoid building of
+Disabling ``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
+dependencies, and ``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_TARGET_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
index 92b52a3..5286d2d 100644
--- a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
+++ b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
@@ -8,7 +8,7 @@ Targets which have their :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` property
``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
+``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.
@@ -16,7 +16,7 @@ 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`
+- additional user defined dependencies from ``AUTOGEN_TARGET_DEPENDS``
See the :manual:`cmake-qt(7)` manual for more information on using CMake
with Qt.
@@ -33,4 +33,4 @@ If :prop_tgt:`AUTOMOC` or :prop_tgt:`AUTOUIC` depends on a file that is either
: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`.
+it must be added to ``AUTOGEN_TARGET_DEPENDS``.
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
index ed8b262..0feb2e8 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -3,7 +3,7 @@ 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
+``AUTOMOC`` is a boolean specifying whether CMake will handle the Qt
``moc`` preprocessor automatically, i.e. without having to use commands like
:module:`QT4_WRAP_CPP() <FindQt4>`, ``QT5_WRAP_CPP()``, etc.
Currently, Qt versions 4 to 6 are supported.
@@ -19,7 +19,7 @@ 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.
+``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
@@ -146,7 +146,7 @@ which is added to the target's sources.
Qt version detection
^^^^^^^^^^^^^^^^^^^^
-:prop_tgt:`AUTOMOC` enabled targets need to know the Qt major and minor
+``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[456]Core`` library,
that the target links to. To find the minor version, CMake builds a list of
@@ -173,7 +173,7 @@ entry in the list is taken.
A ``find_package(Qt[456]...)`` call sets the ``QT/Qt[56]Core_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`
+then the version variables might not be available to the ``AUTOMOC``
enabled target.
In that case the version variables can be forwarded from the
``find_package(Qt[456]...)`` calling context to the :command:`add_executable`
@@ -221,25 +221,25 @@ 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
+Sources and headers can be excluded from ``AUTOMOC`` processing by
setting this source file property.
:prop_sf:`SKIP_AUTOGEN`:
-Source files can be excluded from :prop_tgt:`AUTOMOC`,
+Source files can be excluded from ``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.
+``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`,
+This global property can be used to group ``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
+A global ``autogen`` target, that depends on all ``AUTOMOC`` or
:prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project,
will be generated when this variable is ``ON``.
diff --git a/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst b/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst
index 8998284..82aa61e 100644
--- a/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst
+++ b/Help/prop_tgt/AUTOMOC_COMPILER_PREDEFINES.rst
@@ -12,14 +12,14 @@ from the output of the command defined in
when
- :prop_tgt:`AUTOMOC` is enabled,
-- :prop_tgt:`AUTOMOC_COMPILER_PREDEFINES` is enabled,
+- ``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
+By default ``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
diff --git a/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
index 1f31700..c4277d7 100644
--- a/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
+++ b/Help/prop_tgt/AUTOMOC_DEPEND_FILTERS.rst
@@ -25,7 +25,7 @@ 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
+By default ``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
diff --git a/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
index f4b8396..a6d5aa0 100644
--- a/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
+++ b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
@@ -3,7 +3,7 @@ AUTOMOC_EXECUTABLE
.. versionadded:: 3.14
-:prop_tgt:`AUTOMOC_EXECUTABLE` is file path pointing to the ``moc``
+``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
diff --git a/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst b/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst
index a53810d..072e7f7 100644
--- a/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst
+++ b/Help/prop_tgt/AUTOMOC_MACRO_NAMES.rst
@@ -10,7 +10,7 @@ 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.
+``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
@@ -18,7 +18,7 @@ If any of the strings is found
then the file will be processed by ``moc``.
-By default :prop_tgt:`AUTOMOC_MACRO_NAMES` is initialized from
+By default ``AUTOMOC_MACRO_NAMES`` is initialized from
:variable:`CMAKE_AUTOMOC_MACRO_NAMES`.
See the :manual:`cmake-qt(7)` manual for more information on using CMake
diff --git a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
index 836d953..dcddcae 100644
--- a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
+++ b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst
@@ -14,7 +14,7 @@ compute the relative path accordingly. If the header is not in the
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
+``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
@@ -26,7 +26,7 @@ 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:
+``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
diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst
index 0a0c2a1..33de352 100644
--- a/Help/prop_tgt/AUTORCC.rst
+++ b/Help/prop_tgt/AUTORCC.rst
@@ -3,7 +3,7 @@ AUTORCC
Should the target be processed with auto-rcc (for Qt projects).
-:prop_tgt:`AUTORCC` is a boolean specifying whether CMake will handle
+``AUTORCC`` is a boolean specifying whether CMake will handle
the Qt ``rcc`` code generator automatically, i.e. without having to use
commands like :module:`QT4_ADD_RESOURCES() <FindQt4>`, ``QT5_ADD_RESOURCES()``,
etc. Currently, Qt versions 4 to 6 are supported.
@@ -13,7 +13,7 @@ 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
+By default ``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.
@@ -37,25 +37,25 @@ 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
+``.qrc`` files can be excluded from ``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
+:prop_tgt:`AUTOUIC` and ``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_tgt:`AUTOMOC` or ``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,
+:prop_tgt:`AUTOUIC` and ``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
+A global ``autorcc`` target that depends on all ``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
diff --git a/Help/prop_tgt/AUTORCC_EXECUTABLE.rst b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
index 4f85fba..68942e6 100644
--- a/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
+++ b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
@@ -3,7 +3,7 @@ AUTORCC_EXECUTABLE
.. versionadded:: 3.14
-:prop_tgt:`AUTORCC_EXECUTABLE` is file path pointing to the ``rcc``
+``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
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
index e0cea97..dc854b2 100644
--- a/Help/prop_tgt/AUTOUIC.rst
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -3,7 +3,7 @@ AUTOUIC
Should the target be processed with auto-uic (for Qt projects).
-:prop_tgt:`AUTOUIC` is a boolean specifying whether CMake will handle
+``AUTOUIC`` is a boolean specifying whether CMake will handle
the Qt ``uic`` code generator automatically, i.e. without having to use
commands like :module:`QT4_WRAP_UI() <FindQt4>`, ``QT5_WRAP_UI()``, etc.
Currently, Qt versions 4 to 6 are supported.
@@ -59,22 +59,22 @@ 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
+Source files can be excluded from ``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
+``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,
+``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,
+``AUTOUIC`` generated ``<ORIGIN>_autogen`` targets in the project,
will be generated when this variable is ``ON``.
:prop_tgt:`AUTOGEN_PARALLEL`:
diff --git a/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
index 5966326..be79290 100644
--- a/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
+++ b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
@@ -3,7 +3,7 @@ AUTOUIC_EXECUTABLE
.. versionadded:: 3.14
-:prop_tgt:`AUTOUIC_EXECUTABLE` is file path pointing to the ``uic``
+``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
diff --git a/Help/prop_tgt/BUILD_RPATH.rst b/Help/prop_tgt/BUILD_RPATH.rst
index 1f917a5..902e2f7 100644
--- a/Help/prop_tgt/BUILD_RPATH.rst
+++ b/Help/prop_tgt/BUILD_RPATH.rst
@@ -3,13 +3,34 @@ 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.
+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). By default, CMake sets
+the runtime path of binaries in the build tree to contain search
+paths it knows are needed to find the shared libraries they link.
+Projects may set ``BUILD_RPATH`` to specify additional search paths.
+
+The build-tree runtime path will *not* be used for binaries in the
+install tree. It will be replaced with the install-tree runtime path
+during the installation step. 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)>`.
+
+Other settings that affect the build-tree runtime path include:
+
+* The :variable:`CMAKE_SKIP_RPATH` variable completely disables runtime
+ paths in both the build tree and install tree.
+
+* The :prop_tgt:`SKIP_BUILD_RPATH` target property disables setting any
+ runtime path in the build tree.
+
+* The :prop_tgt:`BUILD_RPATH_USE_ORIGIN` target property causes the
+ automatically-generated runtime path to use entries relative to ``$ORIGIN``.
+
+* The :prop_tgt:`BUILD_WITH_INSTALL_RPATH` target property causes binaries
+ in the build tree to be built with the install-tree runtime path.
diff --git a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
index adfa6f7..7ce0023 100644
--- a/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
+++ b/Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst
@@ -7,13 +7,30 @@ By setting this target property, the target is configured to build with
``C++/CLI`` support.
The Visual Studio generator defines the ``clr`` parameter depending on
-the value of ``COMMON_LANGUAGE_RUNTIME``:
+the value of the ``COMMON_LANGUAGE_RUNTIME`` target property:
-* property not set: native C++ (i.e. default)
-* property set but empty: mixed unmanaged/managed C++
-* property set to any non empty value: managed C++
+Not Set (default)
-Supported values: ``""``, ``"pure"``, ``"safe"``
+ Native C++.
+
+``""`` (set but empty)
+
+ Mixed unmanaged/managed C++ using .NET Framework.
+
+``netcore``
+ .. versionadded:: 3.26
+
+ Mixed unmanaged/managed C++ using .NET Core.
+
+ This required VS 2019's v142 toolset or higher.
+
+``pure``
+
+ Managed C++.
+
+``safe``
+
+ Managed C++.
This property is only evaluated :ref:`Visual Studio Generators` for
VS 2010 and above.
diff --git a/Help/prop_tgt/COMPILE_DEFINITIONS.rst b/Help/prop_tgt/COMPILE_DEFINITIONS.rst
index 059f913..c128a9b 100644
--- a/Help/prop_tgt/COMPILE_DEFINITIONS.rst
+++ b/Help/prop_tgt/COMPILE_DEFINITIONS.rst
@@ -13,6 +13,9 @@ values).
CMake will automatically drop some definitions that are not supported
by the native build tool.
+.. versionadded:: 3.26
+ Any leading ``-D`` on an item will be removed.
+
.. include:: /include/COMPILE_DEFINITIONS_DISCLAIMER.txt
Contents of ``COMPILE_DEFINITIONS`` may use "generator expressions" with the
diff --git a/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst b/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst
index 819ce3e..58072e1 100644
--- a/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst
+++ b/Help/prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS.rst
@@ -14,8 +14,13 @@ 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.
+If this property or :variable:`CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS` is unset,
+static libraries are treated as if it is disabled while shared, module,
+and executable targets behave as if it is on.
+
+If :variable:`CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS` has been defined,
+this property is initialized to the value the variable and overriding
+the default behavior.
Note that device linking is not supported for :ref:`Object Libraries`.
diff --git a/Help/prop_tgt/CXX_SCAN_FOR_MODULES.rst b/Help/prop_tgt/CXX_SCAN_FOR_MODULES.rst
new file mode 100644
index 0000000..e2127c2
--- /dev/null
+++ b/Help/prop_tgt/CXX_SCAN_FOR_MODULES.rst
@@ -0,0 +1,27 @@
+CXX_SCAN_FOR_MODULES
+--------------------
+
+.. versionadded:: 3.26
+
+``CXX_SCAN_FOR_MODULES`` is a boolean specifying whether CMake will scan C++
+sources in the target for module dependencies. See also the
+:prop_sf:`CXX_SCAN_FOR_MODULES` for per-source settings which, if set,
+overrides the target-wide settings.
+
+This property is initialized by the value of the
+:variable:`CMAKE_CXX_SCAN_FOR_MODULES` variable if it is set when a target is
+created.
+
+When this property is set ``ON`` or unset, CMake will scan the target's
+``CXX`` sources at build time and add module dependency information to the
+compile line as necessary. When this property is set ``OFF``, CMake will not
+scan the target's ``CXX`` sources at build time.
+
+Note that scanning is only performed if C++20 or higher is enabled for the
+target. Scanning for modules in the target's sources belonging to file sets
+of type ``CXX_MODULES`` and ``CXX_MODULES_HEADER_UNITS`` is always performed.
+
+.. note ::
+
+ This setting is meaningful only when experimental support for C++ modules
+ has been enabled by the ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` gate.
diff --git a/Help/prop_tgt/DEFINE_SYMBOL.rst b/Help/prop_tgt/DEFINE_SYMBOL.rst
index eb7f937..775cf89 100644
--- a/Help/prop_tgt/DEFINE_SYMBOL.rst
+++ b/Help/prop_tgt/DEFINE_SYMBOL.rst
@@ -8,4 +8,10 @@ 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.
+properly setup dllexport/dllimport decorations on Windows.
+
+On POSIX platforms, this can optionally be used to control the visibility
+of symbols.
+
+CMake provides support for such decorations with the :module:`GenerateExportHeader`
+module.
diff --git a/Help/prop_tgt/FOLDER.rst b/Help/prop_tgt/FOLDER.rst
index f6be9e6..616b962 100644
--- a/Help/prop_tgt/FOLDER.rst
+++ b/Help/prop_tgt/FOLDER.rst
@@ -1,13 +1,20 @@
FOLDER
------
-Set the folder name. Use to organize targets in an IDE.
+For IDEs that present targets using a folder hierarchy, this property
+specifies the name of the folder to place the target under.
+To nest folders, use ``FOLDER`` values such as ``GUI/Dialogs`` with ``/``
+characters separating folder levels. Targets with no ``FOLDER`` property
+will appear as top level entities. Targets with the same ``FOLDER``
+property value will appear in the same folder as siblings.
-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.
+Only some CMake generators honor the ``FOLDER`` property
+(e.g. :generator:`Xcode` or any of the
+:ref:`Visual Studio <Visual Studio Generators>` generators).
+Those generators that don't will simply ignore it.
This property is initialized by the value of the variable
:variable:`CMAKE_FOLDER` if it is set when a target is created.
+
+The global property :prop_gbl:`USE_FOLDERS` must be set to true, otherwise
+the ``FOLDER`` property is ignored.
diff --git a/Help/prop_tgt/INSTALL_NAME_DIR.rst b/Help/prop_tgt/INSTALL_NAME_DIR.rst
index 47a0037..84310b9 100644
--- a/Help/prop_tgt/INSTALL_NAME_DIR.rst
+++ b/Help/prop_tgt/INSTALL_NAME_DIR.rst
@@ -6,8 +6,9 @@ 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.
+by :prop_tgt:`MACOSX_RPATH`. If the :prop_tgt:`BUILD_WITH_INSTALL_NAME_DIR`
+property is set, this will be used already in the build tree.
+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
@@ -16,3 +17,7 @@ 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.
+
+On platforms that support runtime paths (``RPATH``), refer to the
+:prop_tgt:`INSTALL_RPATH` target property.
+Under Windows, the :genex:`TARGET_RUNTIME_DLLS` generator expression is related.
diff --git a/Help/prop_tgt/INSTALL_RPATH.rst b/Help/prop_tgt/INSTALL_RPATH.rst
index 4549b92..e5110b8 100644
--- a/Help/prop_tgt/INSTALL_RPATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH.rst
@@ -3,10 +3,27 @@ INSTALL_RPATH
The rpath to use for installed targets.
-A semicolon-separated list specifying the rpath to use in installed
+By default, the install rpath is empty. It can be set using this property,
+which is 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.
+by the value of the variable :variable:`CMAKE_INSTALL_RPATH` if it is set
+when a target is created.
+Beside setting the install rpath manually, using the
+:prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` target property it can also be
+generated automatically by CMake.
+
+Normally CMake uses the build tree for the RPATH when building executables
+etc on systems that use RPATH, see the :prop_tgt:`BUILD_RPATH` target
+property. When the software is installed
+the targets are edited (or relinked) by CMake (see
+:variable:`CMAKE_NO_BUILTIN_CHRPATH`) to have the install RPATH.
+This editing during installation can be avoided via
+the :prop_tgt:`BUILD_WITH_INSTALL_RPATH` target property.
+
+For handling toolchain-dependent RPATH entries the
+:prop_tgt:`INSTALL_REMOVE_ENVIRONMENT_RPATH` can be used.
+Runtime paths can be disabled completely via the :variable:`CMAKE_SKIP_RPATH`
+variable.
Because the rpath may contain ``${ORIGIN}``, which coincides with CMake syntax,
the contents of ``INSTALL_RPATH`` are properly escaped in the
@@ -14,3 +31,6 @@ the contents of ``INSTALL_RPATH`` are properly escaped in the
This property supports
:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+On Apple platforms, refer to the :prop_tgt:`INSTALL_NAME_DIR` target property.
+Under Windows, the :genex:`TARGET_RUNTIME_DLLS` generator expression is related.
diff --git a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
index d16a7a1..ef859cf 100644
--- a/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/prop_tgt/INSTALL_RPATH_USE_LINK_PATH.rst
@@ -3,7 +3,7 @@ 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``
+``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
diff --git a/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst b/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst
index c74a319..9cc12a1 100644
--- a/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst
+++ b/Help/prop_tgt/INTERFACE_COMPILE_DEFINITIONS.rst
@@ -5,5 +5,4 @@ INTERFACE_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
index 0db3b0c..50d6161 100644
--- a/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
+++ b/Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
@@ -7,7 +7,6 @@ INTERFACE_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
diff --git a/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst b/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst
index 7f0b385..2af7a99 100644
--- a/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst
+++ b/Help/prop_tgt/INTERFACE_COMPILE_OPTIONS.rst
@@ -5,5 +5,4 @@ INTERFACE_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
index b1c40b2..8795c80 100644
--- a/Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst
+++ b/Help/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.rst
@@ -5,7 +5,6 @@ INTERFACE_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
diff --git a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
index de1dabb..45b3225 100644
--- a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
@@ -7,5 +7,4 @@ INTERFACE_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_OPTIONS.rst b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
index 4245fe9..785b17c 100644
--- a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
@@ -7,5 +7,4 @@ INTERFACE_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/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
index d3a5e94..0a4ac9a 100644
--- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst
@@ -11,3 +11,7 @@ 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.
+
+There is also the per-configuration :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>`
+target property, which overrides :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION`
+if it is set.
diff --git a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
index 42cace0..fab142c 100644
--- a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
+++ b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
@@ -18,6 +18,6 @@ For instance:
This property is initialized by the value of
:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER`.
-If neither :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER` nor
+If neither ``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/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst b/Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst
new file mode 100644
index 0000000..fc88f0f
--- /dev/null
+++ b/Help/prop_tgt/LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst
@@ -0,0 +1,29 @@
+<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR
+----------------------------------
+
+.. versionadded:: 3.26
+
+This property is implemented only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC``
+or ``OBJCXX``, and only has an effect when :prop_tgt:`<LANG>_CLANG_TIDY` is
+set.
+
+Specify a directory for the ``clang-tidy`` tool to put ``.yaml`` files
+containing its suggested changes in. This can be used for automated mass
+refactoring by ``clang-tidy``. Each object file that gets compiled will have a
+corresponding ``.yaml`` file in this directory. After the build is completed,
+you can run ``clang-apply-replacements`` on this directory to simultaneously
+apply all suggested changes to the code base. If this property is not an
+absolute directory, it is assumed to be relative to the target's binary
+directory. This property should be preferred over adding an ``--export-fixes``
+or ``--fix`` argument directly to the :prop_tgt:`<LANG>_CLANG_TIDY` property.
+
+When this property is set, CMake takes ownership of the specified directory,
+and may create, modify, or delete files and directories within the directory
+at any time during configure or build time. Users should use a dedicated
+directory for exporting clang-tidy fixes to avoid having files deleted or
+overwritten by CMake. Users should not create, modify, or delete files in this
+directory.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/LINK_OPTIONS.rst b/Help/prop_tgt/LINK_OPTIONS.rst
index 27eadf9..fcdac59 100644
--- a/Help/prop_tgt/LINK_OPTIONS.rst
+++ b/Help/prop_tgt/LINK_OPTIONS.rst
@@ -9,8 +9,8 @@ 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.
+link steps, :genex:`$<HOST_LINK>` and :genex:`$<DEVICE_LINK>` generator
+expressions 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`
diff --git a/Help/prop_tgt/OBJCXX_EXTENSIONS.rst b/Help/prop_tgt/OBJCXX_EXTENSIONS.rst
index 2a15dec..9a629fd 100644
--- a/Help/prop_tgt/OBJCXX_EXTENSIONS.rst
+++ b/Help/prop_tgt/OBJCXX_EXTENSIONS.rst
@@ -15,7 +15,7 @@ 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`.
+the value of :prop_tgt:`CXX_EXTENSIONS` is set for ``OBJCXX_EXTENSIONS``.
This property is initialized by the value of
the :variable:`CMAKE_OBJCXX_EXTENSIONS` variable if set when a target is
diff --git a/Help/prop_tgt/OBJCXX_STANDARD.rst b/Help/prop_tgt/OBJCXX_STANDARD.rst
index 6ac8216..03108e1 100644
--- a/Help/prop_tgt/OBJCXX_STANDARD.rst
+++ b/Help/prop_tgt/OBJCXX_STANDARD.rst
@@ -53,7 +53,7 @@ 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`.
+the value of :prop_tgt:`CXX_STANDARD` is set for ``OBJCXX_STANDARD``.
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/OBJCXX_STANDARD_REQUIRED.rst b/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst
index 3cee740..2c3c77c 100644
--- a/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst
+++ b/Help/prop_tgt/OBJCXX_STANDARD_REQUIRED.rst
@@ -12,7 +12,7 @@ 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`.
+the value of :prop_tgt:`CXX_STANDARD_REQUIRED` is set for ``OBJCXX_STANDARD_REQUIRED``.
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/OBJC_EXTENSIONS.rst b/Help/prop_tgt/OBJC_EXTENSIONS.rst
index cd72e5f..2914045 100644
--- a/Help/prop_tgt/OBJC_EXTENSIONS.rst
+++ b/Help/prop_tgt/OBJC_EXTENSIONS.rst
@@ -12,7 +12,7 @@ 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`.
+the value of :prop_tgt:`C_EXTENSIONS` is set for ``OBJC_EXTENSIONS``.
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/OBJC_STANDARD.rst b/Help/prop_tgt/OBJC_STANDARD.rst
index 2d27bcf..0609239 100644
--- a/Help/prop_tgt/OBJC_STANDARD.rst
+++ b/Help/prop_tgt/OBJC_STANDARD.rst
@@ -36,7 +36,7 @@ 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`.
+the value of :prop_tgt:`C_STANDARD` is set for ``OBJC_STANDARD``.
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/OBJC_STANDARD_REQUIRED.rst b/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst
index 11547c8..8b0a928 100644
--- a/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst
+++ b/Help/prop_tgt/OBJC_STANDARD_REQUIRED.rst
@@ -12,7 +12,7 @@ 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`.
+the value of :prop_tgt:`C_STANDARD_REQUIRED` is set for ``OBJC_STANDARD_REQUIRED``.
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/SKIP_BUILD_RPATH.rst b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
index 7086b1b..1fe170c 100644
--- a/Help/prop_tgt/SKIP_BUILD_RPATH.rst
+++ b/Help/prop_tgt/SKIP_BUILD_RPATH.rst
@@ -4,6 +4,7 @@ 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.
+generation of an rpath allowing the target to run from the build tree,
+see also the :prop_tgt:`BUILD_RPATH` target property.
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/UNITY_BUILD_MODE.rst b/Help/prop_tgt/UNITY_BUILD_MODE.rst
index 003451e..d3d1fcc 100644
--- a/Help/prop_tgt/UNITY_BUILD_MODE.rst
+++ b/Help/prop_tgt/UNITY_BUILD_MODE.rst
@@ -56,5 +56,5 @@ which has the following acceptable values:
PROPERTIES UNITY_GROUP "bucket2"
)
-If no explicit :prop_tgt:`UNITY_BUILD_MODE` has been specified, CMake will
+If no explicit ``UNITY_BUILD_MODE`` has been specified, CMake will
default to ``BATCH``.
diff --git a/Help/prop_tgt/XCODE_EMBED_type.rst b/Help/prop_tgt/XCODE_EMBED_type.rst
index e8383c2..da744c2 100644
--- a/Help/prop_tgt/XCODE_EMBED_type.rst
+++ b/Help/prop_tgt/XCODE_EMBED_type.rst
@@ -16,9 +16,21 @@ The supported values for ``<type>`` are:
``APP_EXTENSIONS``
.. versionadded:: 3.21
- The specified items will be added to the ``Embed App Extensions`` build phase.
+ The specified items will be added to the ``Embed App Extensions`` build
+ phase, with ``Destination`` set to ``PlugIns and Foundation Extensions``
They must be CMake target names.
+``EXTENSIONKIT_EXTENSIONS``
+ .. versionadded:: 3.26
+
+ The specified items will be added to the ``Embed App Extensions`` build
+ phase, with ``Destination`` set to ``ExtensionKit Extensions``
+ They must be CMake target names, and should likely have the
+ ``XCODE_PRODUCT_TYPE`` target property set to
+ ``com.apple.product-type.extensionkit-extension``
+ as well as the ``XCODE_EXPLICIT_FILE_TYPE`` to
+ ``wrapper.extensionkit-extension``
+
``PLUGINS``
.. versionadded:: 3.23
diff --git a/Help/prop_tgt/XCODE_EMBED_type_CODE_SIGN_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_type_CODE_SIGN_ON_COPY.rst
index cb449ac..ca35c25 100644
--- a/Help/prop_tgt/XCODE_EMBED_type_CODE_SIGN_ON_COPY.rst
+++ b/Help/prop_tgt/XCODE_EMBED_type_CODE_SIGN_ON_COPY.rst
@@ -14,6 +14,9 @@ The supported values for ``<type>`` are:
``APP_EXTENSIONS``
.. versionadded:: 3.21
+``EXTENSIONKIT_EXTENSIONS``
+ .. versionadded:: 3.26
+
``PLUGINS``
.. versionadded:: 3.23
diff --git a/Help/prop_tgt/XCODE_EMBED_type_PATH.rst b/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
index 160f765..5a5c65f 100644
--- a/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
+++ b/Help/prop_tgt/XCODE_EMBED_type_PATH.rst
@@ -17,5 +17,8 @@ The supported values for ``<type>`` are:
``APP_EXTENSIONS``
.. versionadded:: 3.21
+``EXTENSIONKIT_EXTENSIONS``
+ .. versionadded:: 3.26
+
``PLUGINS``
.. versionadded:: 3.23
diff --git a/Help/prop_tgt/XCODE_EMBED_type_REMOVE_HEADERS_ON_COPY.rst b/Help/prop_tgt/XCODE_EMBED_type_REMOVE_HEADERS_ON_COPY.rst
index e3a7ced..da8f61b 100644
--- a/Help/prop_tgt/XCODE_EMBED_type_REMOVE_HEADERS_ON_COPY.rst
+++ b/Help/prop_tgt/XCODE_EMBED_type_REMOVE_HEADERS_ON_COPY.rst
@@ -19,5 +19,11 @@ The supported values for ``<type>`` are:
If the ``XCODE_EMBED_APP_EXTENSIONS_REMOVE_HEADERS_ON_COPY`` property is not
defined, headers WILL be removed on copy by default.
+``EXTENSIONKIT_EXTENSIONS``
+ .. versionadded:: 3.26
+
+ If the ``XCODE_EMBED_APP_EXTENSIONS_REMOVE_HEADERS_ON_COPY`` property is not
+ defined, headers WILL be removed on copy by default.
+
``PLUGINS``
.. versionadded:: 3.23
diff --git a/Help/release/3.15.rst b/Help/release/3.15.rst
index 6b1a800..de3ced0 100644
--- a/Help/release/3.15.rst
+++ b/Help/release/3.15.rst
@@ -243,46 +243,42 @@ Modules
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 generator expressions :genex:`$<C_COMPILER_ID>`,
+ :genex:`$<CXX_COMPILER_ID>`, :genex:`$<CUDA_COMPILER_ID>`,
+ :genex:`$<Fortran_COMPILER_ID>`, :genex:`$<COMPILE_LANGUAGE>`,
+ :genex:`$<COMPILE_LANG_AND_ID>`, and :genex:`$<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 :genex:`$<CUDA_COMPILER_ID:...>` and :genex:`$<CUDA_COMPILER_VERSION:...>`
+ generator expressions were added.
-* The ``$<COMPILE_LANG_AND_ID:...>`` generator expression was introduced to
+* The :genex:`$<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 :genex:`$<FILTER:list,INCLUDE|EXCLUDE,regex>` generator expression has
+ been added.
-* A ``$<REMOVE_DUPLICATES:list>``
- :manual:`generator expression <cmake-generator-expressions(7)>`
- has been added.
+* A :genex:`$<REMOVE_DUPLICATES:list>` generator expression has been added.
-* The ``$<SHELL_PATH:...>`` :manual:`generator expression
- <cmake-generator-expressions(7)>` gained support for a list of paths.
+* The :genex:`$<SHELL_PATH:...>` generator expression 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.
+ * :genex:`$<TARGET_FILE_PREFIX:...>`
+ * :genex:`$<TARGET_FILE_BASE_NAME:...>`
+ * :genex:`$<TARGET_FILE_SUFFIX:...>`
+ * :genex:`$<TARGET_LINKER_FILE_PREFIX:...>`
+ * :genex:`$<TARGET_LINKER_FILE_BASE_NAME:...>`
+ * :genex:`$<TARGET_LINKER_FILE_SUFFIX:...>`
+ * :genex:`$<TARGET_PDB_FILE_BASE_NAME:...>`
+
+* The :genex:`$<TARGET_OBJECTS:...>` generator expression is now supported
+ on ``SHARED``, ``STATIC``, ``MODULE`` libraries and executables.
CTest
-----
diff --git a/Help/release/3.17.rst b/Help/release/3.17.rst
index 1aa475f..a27d638 100644
--- a/Help/release/3.17.rst
+++ b/Help/release/3.17.rst
@@ -140,7 +140,7 @@ Properties
* 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
+ In particular, the :genex:`$<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
diff --git a/Help/release/3.18.rst b/Help/release/3.18.rst
index f97e4df..c120b9f 100644
--- a/Help/release/3.18.rst
+++ b/Help/release/3.18.rst
@@ -211,12 +211,11 @@ Modules
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 :genex:`$<DEVICE_LINK:...>` and :genex:`$<HOST_LINK:...>`
+ generator expressions 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.
+* The :genex:`$<LINK_LANGUAGE:...>` and :genex:`$<LINK_LANG_AND_ID:...>`
+ generator expressions were added.
CTest
-----
diff --git a/Help/release/3.20.rst b/Help/release/3.20.rst
index 40cac41..ebd0f91 100644
--- a/Help/release/3.20.rst
+++ b/Help/release/3.20.rst
@@ -86,8 +86,8 @@ Commands
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
+ support for new generator expressions :genex:`$<COMMAND_CONFIG:...>` and
+ :genex:`$<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
diff --git a/Help/release/3.23.rst b/Help/release/3.23.rst
index 6376d77..5d85777 100644
--- a/Help/release/3.23.rst
+++ b/Help/release/3.23.rst
@@ -274,8 +274,8 @@ Other Changes
* tries to detect invalid architectures and issue an error.
* ``CUDA`` with Clang now implements policy :policy:`CMP0105` and
- the ``$<DEVICE_LINK:...>`` and ``$<HOST_LINK:...>``
- :manual:`generator expressions <cmake-generator-expressions(7)>`.
+ the :genex:`$<DEVICE_LINK:...>` and :genex:`$<HOST_LINK:...>`
+ generator expressions.
* The :command:`define_property` command's ``BRIEF_DOCS`` and ``FULL_DOCS``
arguments are now optional.
diff --git a/Help/release/3.26.rst b/Help/release/3.26.rst
new file mode 100644
index 0000000..ee98a98
--- /dev/null
+++ b/Help/release/3.26.rst
@@ -0,0 +1,171 @@
+CMake 3.26 Release Notes
+************************
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake 3.25 include the following.
+
+New Features
+============
+
+Languages
+---------
+
+* The ``ASM_MARMASM`` language was added to support the
+ Microsoft ARM assembler language.
+
+Command-Line
+------------
+
+* The :option:`cmake -E copy <cmake-E copy>` command-line tool now
+ supports a ``-t`` argument.
+
+* The :option:`cmake -E copy_directory_if_different
+ <cmake-E copy_directory_if_different>` command-line tool was added.
+
+Configure Log
+-------------
+
+* CMake now writes a YAML log of configure-time checks to
+ ``CMakeFiles/CMakeConfigureLog.yaml`` under the top of the build tree.
+ See the :manual:`cmake-configure-log(7)` manual.
+
+File-Based API
+--------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+ been updated to 2.5.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object
+ gained a new ``fileSets`` field and associated ``fileSetIndex``
+ field to ``sources`` objects.
+
+* The :manual:`cmake-file-api(7)` gained a new "configureLog" object kind
+ that enables stable access to the :manual:`cmake-configure-log(7)`.
+
+Commands
+--------
+
+* The :command:`add_custom_command` and :command:`add_custom_target` commands
+ now support :manual:`generator expressions <cmake-generator-expressions(7)>`
+ in their ``COMMENT`` option.
+
+* The :command:`message` command gained a ``CONFIGURE_LOG`` mode to
+ record an entry in the :manual:`cmake-configure-log(7)`.
+
+* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` commands
+ now support the ``%z`` and ``%Z`` specifiers for the time zone.
+
+* The :command:`try_compile` and :command:`try_run` commands gained
+ a ``LOG_DESCRIPTION`` option specifying text to be recorded in the
+ :manual:`cmake-configure-log(7)`.
+
+* The :command:`try_compile` and :command:`try_run` commands gained a
+ ``NO_LOG`` option to skip recording a :manual:`cmake-configure-log(7)`
+ entry.
+
+Variables
+---------
+
+* The :variable:`CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT` variable is now
+ set for ``GNU``, ``MSVC``, and ``AppleClang`` compilers that have only
+ one frontend variant.
+
+* A :variable:`CMAKE_VS_VERSION_BUILD_NUMBER` variable is now set by
+ :ref:`Visual Studio Generators` for VS 2017 and above to report the
+ four-component Visual Studio version number.
+
+Properties
+----------
+
+* The :prop_tgt:`<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` target property was
+ added to allow the ``clang-tidy`` tool to export its suggested fixes to a
+ set of ``.yaml`` files. A new
+ :variable:`CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` variable was created to
+ initialize this property.
+
+* The :prop_tgt:`XCODE_EMBED_EXTENSIONKIT_EXTENSIONS <XCODE_EMBED_<type>>`
+ target property was added to tell the :generator:`Xcode` generator to embed
+ ExtensionKit-based extensions such as extensions using the Background
+ Assets framework. Aspects of the embedding can be customized with:
+
+ * :prop_tgt:`XCODE_EMBED_EXTENSIONKIT_EXTENSIONS_PATH <XCODE_EMBED_<type>>`
+ * :prop_tgt:`XCODE_EMBED_EXTENSIONKIT_EXTENSIONS_CODE_SIGN_ON_COPY <XCODE_EMBED_<type>_CODE_SIGN_ON_COPY>`
+ * :prop_tgt:`XCODE_EMBED_EXTENSIONKIT_EXTENSIONS_REMOVE_HEADERS_ON_COPY <XCODE_EMBED_<type>_REMOVE_HEADERS_ON_COPY>`
+
+Modules
+-------
+
+* The :module:`ExternalProject` module's :command:`ExternalProject_Add` command
+ gained an ``INSTALL_BYPRODUCTS`` option to specify files generated by the
+ ``install`` step.
+
+* The :module:`FindCUDAToolkit` module:
+
+ * gained support for the ``sbsa-linux`` cross compilation target, and
+
+ * now provides an imported target for ``nvrtc_static``, if found.
+
+* The :module:`FindImageMagick` module now provides imported targets.
+
+* The :module:`FindPython3` and :module:`FindPython` modules gained
+ support for the `Stable Application Binary Interface`_.
+
+* The :module:`UseSWIG` module gained support for the ``perl5`` language.
+
+.. _`Stable Application Binary Interface`: https://docs.python.org/3/c-api/stable.html
+
+Generator Expressions
+---------------------
+
+* The :genex:`$<BUILD_LOCAL_INTERFACE:...>` generator expression was added to
+ prevent usage requirements from being exported to dependent projects.
+
+CTest
+-----
+
+* The :envvar:`CTEST_NO_TESTS_ACTION` environment variable was added to
+ provide a default value for the
+ :option:`--no-tests=\<action\> <ctest --no-tests>` command line
+ argument of :manual:`ctest(1)`.
+
+Deprecated and Removed Features
+===============================
+
+* The ``CMakeFiles/CMakeOutput.log`` and ``CMakeFiles/CMakeError.log``
+ files are no longer populated by CMake's built-in modules.
+ :manual:`cmake(1)` no longer suggests looking at them after a
+ ``CMake Error`` occurs. Information previously logged to those
+ files is instead logged to the :manual:`cmake-configure-log(7)`.
+
+* On CYGWIN, the undocumented ``CMAKE_LEGACY_CYGWIN_WIN32`` mode for
+ compatibility with CMake versions older than 2.8.4 has been removed.
+
+Other Changes
+=============
+
+* :ref:`Language Standard Flags`, such as ``-std=c++11``, when generated due
+ to :command:`target_compile_features` or :variable:`CMAKE_<LANG>_STANDARD`,
+ are now placed before flags added by :command:`target_compile_options`,
+ rather than after them.
+
+* For all ``COMPILE_DEFINITIONS`` properties, any leading ``-D`` on an item
+ is removed whether or not it was specified by a generator expression.
+
+* The ``compile_commands.json`` database enabled by
+ :variable:`CMAKE_EXPORT_COMPILE_COMMANDS` now provides the ``output``
+ field in the compile commands objects. This allows multi-config
+ generators, such as the :generator:`Ninja Multi-Config` generator,
+ to provide the compile commands for all configurations.
+
+* The :prop_gbl:`USE_FOLDERS` global property is treated as ``ON`` by default.
+ See policy :policy:`CMP0143`.
+
+* The top-level :command:`project` call will now emit an author warning if the
+ documented command order in relation to :command:`cmake_minimum_required` is
+ not respected.
+
+* The :option:`cmake --trace` option now follows :command:`try_compile` and
+ :command:`try_run` invocations.
diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst
index 89da627..09e4ea6 100644
--- a/Help/release/3.9.rst
+++ b/Help/release/3.9.rst
@@ -256,11 +256,11 @@ Other
:command:`file(GENERATE)` commands.
* Two new informational generator expressions to retrieve Apple Bundle
- directories have been added. The first one ``$<TARGET_BUNDLE_DIR:tgt>``
+ directories have been added. The first one :genex:`$<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
+ :genex:`$<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>``.
+ bundle types and SDKs it is identical with :genex:`$<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.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index b6ecf7b..c82889f 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -13,6 +13,7 @@ Releases
.. toctree::
:maxdepth: 1
+ 3.26 <3.26>
3.25 <3.25>
3.24 <3.24>
3.23 <3.23>
diff --git a/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst b/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst
index c24e462..f490974 100644
--- a/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst
+++ b/Help/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS.rst
@@ -10,4 +10,4 @@ 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``.
+By default ``CMAKE_AUTOGEN_ORIGIN_DEPENDS`` is ``ON``.
diff --git a/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
index 2ada012..8e68579 100644
--- a/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
+++ b/Help/variable/CMAKE_AUTOGEN_PARALLEL.rst
@@ -9,4 +9,4 @@ Number of parallel ``moc`` or ``uic`` processes to start when using
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.
+By default ``CMAKE_AUTOGEN_PARALLEL`` is unset.
diff --git a/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst b/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst
index f77ed6a..246bd37 100644
--- a/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst
+++ b/Help/variable/CMAKE_AUTOGEN_VERBOSE.rst
@@ -7,9 +7,9 @@ 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
+Setting ``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.
+By default ``CMAKE_AUTOGEN_VERBOSE`` is unset.
diff --git a/Help/variable/CMAKE_BINARY_DIR.rst b/Help/variable/CMAKE_BINARY_DIR.rst
index e601eb8..96c6319 100644
--- a/Help/variable/CMAKE_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_BINARY_DIR.rst
@@ -8,6 +8,6 @@ tree. For an in-source build, this would be the same as
:variable:`CMAKE_SOURCE_DIR`.
When run in :option:`cmake -P` script mode, CMake sets the variables
-:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+``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_WITH_INSTALL_RPATH.rst b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
index 5b59a6e..839771a 100644
--- a/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
+++ b/Help/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.rst
@@ -9,3 +9,6 @@ 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.
+
+This is used to initialize the :prop_tgt:`BUILD_WITH_INSTALL_RPATH` target property
+for all targets.
diff --git a/Help/variable/CMAKE_CONFIGURATION_TYPES.rst b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
index 75ff8a1..887eb2f 100644
--- a/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
+++ b/Help/variable/CMAKE_CONFIGURATION_TYPES.rst
@@ -3,7 +3,8 @@ CMAKE_CONFIGURATION_TYPES
Specifies the available build types (configurations) on multi-config
generators (e.g. :ref:`Visual Studio <Visual Studio Generators>`,
-:generator:`Xcode`, or :generator:`Ninja Multi-Config`). Typical values
+:generator:`Xcode`, or :generator:`Ninja Multi-Config`) as a
+:ref:`semicolon-separated list <CMake Language Lists>`. Typical entries
include ``Debug``, ``Release``, ``RelWithDebInfo`` and ``MinSizeRel``,
but custom build types can also be defined.
diff --git a/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst b/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst
index 474baee..bd56911 100644
--- a/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst
+++ b/Help/variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS.rst
@@ -4,5 +4,7 @@ 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
+property when defined. By default this variable is not defined.
+
+This variable is used to initialize the property on each target as
it is created.
diff --git a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
index 15f81d2..1d7a111 100644
--- a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
@@ -11,5 +11,5 @@ current source directory being processed.
When run in :option:`cmake -P` script mode, CMake sets the variables
:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
-:variable:`CMAKE_CURRENT_BINARY_DIR` and
+``CMAKE_CURRENT_BINARY_DIR`` and
:variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
diff --git a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
index 5b86026..4205efb 100644
--- a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
@@ -9,4 +9,4 @@ processed by cmake.
When run in :option:`cmake -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.
+``CMAKE_CURRENT_SOURCE_DIR`` to the current working directory.
diff --git a/Help/variable/CMAKE_CXX_SCAN_FOR_MODULES.rst b/Help/variable/CMAKE_CXX_SCAN_FOR_MODULES.rst
new file mode 100644
index 0000000..a40bf75
--- /dev/null
+++ b/Help/variable/CMAKE_CXX_SCAN_FOR_MODULES.rst
@@ -0,0 +1,15 @@
+CMAKE_CXX_SCAN_FOR_MODULES
+--------------------------
+
+.. versionadded:: 3.26
+
+Whether to scan C++ source files for module dependencies.
+
+This variable is used to initialize the :prop_tgt:`CXX_SCAN_FOR_MODULES`
+property on all the targets. See that target property for additional
+information.
+
+.. note ::
+
+ This setting is meaningful only when experimental support for C++ modules
+ has been enabled by the ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API`` gate.
diff --git a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
index 65a5f0d..2f42b23 100644
--- a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
+++ b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
@@ -10,7 +10,7 @@ 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
+but set ``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.
diff --git a/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
index bdad59e..ada4ba6 100644
--- a/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
+++ b/Help/variable/CMAKE_DEPENDS_USE_COMPILER.rst
@@ -6,4 +6,4 @@ CMAKE_DEPENDS_USE_COMPILER
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).
+CMake for dependencies discovery).
diff --git a/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst b/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst
index fc28ebb..612ab8a 100644
--- a/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst
+++ b/Help/variable/CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT.rst
@@ -9,5 +9,5 @@ This cache variable is used by the Eclipse project generator. See
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
+``CMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT`` defaults to ``FALSE``; so
nothing is written into the source directory.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst
index 8d86a94..5392ad1 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY.rst
@@ -18,7 +18,7 @@ unless the ``NO_CMAKE_PACKAGE_REGISTRY`` option is provided.
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`
+for packages. If the ``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.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst
index cc67f08..21b0230 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY.rst
@@ -18,7 +18,7 @@ unless the ``NO_CMAKE_SYSTEM_PACKAGE_REGISTRY`` option is provided.
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
+``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.
diff --git a/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst b/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst
index a5eec7a..b058ba0 100644
--- a/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst
+++ b/Help/variable/CMAKE_FIND_USE_PACKAGE_REGISTRY.rst
@@ -18,7 +18,7 @@ This variable takes precedence over
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`
+for packages. If the ``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.
diff --git a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
index 6bfabe0..4317622 100644
--- a/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
+++ b/Help/variable/CMAKE_GENERATOR_INSTANCE.rst
@@ -43,24 +43,8 @@ Supported pairs are:
.. versionadded:: 3.23
Specify the 4-component VS Build Version, a.k.a. Build Number.
- The components are:
- ``<major>.<minor>``
-
- The VS major and minor version numbers.
- These are the same as the release version numbers.
-
- ``<date>``
-
- A build date in the format ``MMMDD``, where ``MMM`` is a month index
- since an epoch used by Microsoft, and ``DD`` is a day in that month.
-
- ``<build>``
-
- A build index on the day represented by ``<date>``.
-
- The build number is reported by ``vswhere`` as ``installationVersion``.
- For example, VS 16.11.10 has build number ``16.11.32126.315``.
+ .. include:: CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt
.. versionadded:: 3.23
@@ -75,3 +59,6 @@ to hold the value persistently. If an environment variable of the form
is set and points to the ``Common7/Tools`` directory within one of the
VS instances, that instance will be used. Otherwise, if more than one
VS instance is installed we do not define which one is chosen by default.
+
+The VS version build number of the selected VS instance is provided in
+the :variable:`CMAKE_VS_VERSION_BUILD_NUMBER` variable.
diff --git a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
index 96e9907..7d3f9c3 100644
--- a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
+++ b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
@@ -5,7 +5,7 @@ CMAKE_GLOBAL_AUTOGEN_TARGET
Switch to enable generation of a global ``autogen`` target.
-When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a custom target
+When ``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
@@ -14,7 +14,7 @@ By building the global ``autogen`` target, all :prop_tgt:`AUTOMOC` and
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.
+By default ``CMAKE_GLOBAL_AUTOGEN_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_AUTOGEN_TARGET_NAME.rst b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
index 4af4bc3..d970d56 100644
--- a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
+++ b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET_NAME.rst
@@ -6,10 +6,10 @@ CMAKE_GLOBAL_AUTOGEN_TARGET_NAME
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`
+named ``autogen`` is created. ``CMAKE_GLOBAL_AUTOGEN_TARGET_NAME``
allows to set a different name for that target.
-By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+By default ``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
index efea5be..0b8c309 100644
--- a/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst
+++ b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET.rst
@@ -5,7 +5,7 @@ CMAKE_GLOBAL_AUTORCC_TARGET
Switch to enable generation of a global ``autorcc`` target.
-When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
+When ``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`
@@ -14,7 +14,7 @@ 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.
+By default ``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
index 4d2e313..742425f 100644
--- a/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst
+++ b/Help/variable/CMAKE_GLOBAL_AUTORCC_TARGET_NAME.rst
@@ -6,10 +6,10 @@ CMAKE_GLOBAL_AUTORCC_TARGET_NAME
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`
+named ``autorcc`` is created. ``CMAKE_GLOBAL_AUTORCC_TARGET_NAME``
allows to set a different name for that target.
-By default :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET_NAME` is unset.
+By default ``CMAKE_GLOBAL_AUTORCC_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_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst b/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
index aad99e4..f864c20 100644
--- a/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
+++ b/Help/variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS.rst
@@ -7,7 +7,7 @@ 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`
+get permissions set by ``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
@@ -15,7 +15,7 @@ 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`
+Expected content of the ``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS``
variable is a list of permissions that can be used by :command:`install` command
`PERMISSIONS` section.
diff --git a/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst b/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst
new file mode 100644
index 0000000..60b7f40
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_CLANG_TIDY_EXPORT_FIXES_DIR.rst
@@ -0,0 +1,15 @@
+CMAKE_<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR
+----------------------------------------
+
+.. versionadded:: 3.26
+
+Default value for :prop_tgt:`<LANG>_CLANG_TIDY_EXPORT_FIXES_DIR` 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_EXPORT_FIXES_DIR clang-tidy-fixes)
+ add_executable(foo foo.cxx)
diff --git a/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst b/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst
index 128b1fb..a414463 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_FRONTEND_VARIANT.rst
@@ -16,3 +16,7 @@ the compiler whose frontend it resembles.
.. note::
In other words, this variable describes what command line options
and language extensions the compiler frontend expects.
+
+.. versionchanged:: 3.26
+ This variable is set for ``GNU``, ``MSVC``, and ``AppleClang``
+ compilers that have only one frontend variant.
diff --git a/Help/variable/CMAKE_MODULE_PATH.rst b/Help/variable/CMAKE_MODULE_PATH.rst
index 4dcf6b5..3021b49 100644
--- a/Help/variable/CMAKE_MODULE_PATH.rst
+++ b/Help/variable/CMAKE_MODULE_PATH.rst
@@ -1,7 +1,8 @@
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.
+:ref:`Semicolon-separated list <CMake Language Lists>` of directories,
+represented using forward slashes, 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_NO_BUILTIN_CHRPATH.rst b/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
index b9b045e..483ec5f 100644
--- a/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
+++ b/Help/variable/CMAKE_NO_BUILTIN_CHRPATH.rst
@@ -10,6 +10,9 @@ 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.
+For more information on RPATH handling see
+the :prop_tgt:`INSTALL_RPATH` and :prop_tgt:`BUILD_RPATH` target properties.
+
.. versionadded:: 3.20
This variable also applies to XCOFF binaries' LIBPATH. Prior to the
diff --git a/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst b/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst
index 8da6100..dd3e2a0 100644
--- a/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst
+++ b/Help/variable/CMAKE_SKIP_BUILD_RPATH.rst
@@ -6,5 +6,13 @@ 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
+install RPATH. If this variable is set to ``TRUE`` then the software is
always built with no RPATH.
+
+This is used to initialize the :prop_tgt:`SKIP_BUILD_RPATH` target property
+for all targets. For more information on RPATH handling see
+the :prop_tgt:`INSTALL_RPATH` and :prop_tgt:`BUILD_RPATH` target properties.
+
+See also the :variable:`CMAKE_SKIP_INSTALL_RPATH` variable.
+To omit RPATH in both the build and install steps, use
+:variable:`CMAKE_SKIP_RPATH` instead.
diff --git a/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
index 80a68c9..e88db36 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY.rst
@@ -6,6 +6,6 @@ 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
+If ``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
index cc0ac21..465fdae 100644
--- a/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
+++ b/Help/variable/CMAKE_SKIP_INSTALL_RPATH.rst
@@ -10,5 +10,10 @@ 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.
+
+See also the :variable:`CMAKE_SKIP_BUILD_RPATH` variable.
To omit RPATH in both the build and install steps, use
:variable:`CMAKE_SKIP_RPATH` instead.
+
+For more information on RPATH handling see the :prop_tgt:`INSTALL_RPATH`
+and :prop_tgt:`BUILD_RPATH` target properties.
diff --git a/Help/variable/CMAKE_SKIP_RPATH.rst b/Help/variable/CMAKE_SKIP_RPATH.rst
index d7ce8e4..43f6401 100644
--- a/Help/variable/CMAKE_SKIP_RPATH.rst
+++ b/Help/variable/CMAKE_SKIP_RPATH.rst
@@ -7,4 +7,8 @@ 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.
+:variable:`CMAKE_SKIP_INSTALL_RPATH` instead. To omit RPATH in the build step,
+use :variable:`CMAKE_SKIP_BUILD_RPATH`.
+
+For more information on RPATH handling see the :prop_tgt:`INSTALL_RPATH`
+and :prop_tgt:`BUILD_RPATH` target properties.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index 7210f75..f1d1bee 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -8,6 +8,6 @@ tree. For an in-source build, this would be the same as
:variable:`CMAKE_BINARY_DIR`.
When run in :option:`cmake -P` script mode, CMake sets the variables
-:variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
+:variable:`CMAKE_BINARY_DIR`, ``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
index bdb97fa..7b1048b 100644
--- a/Help/variable/CMAKE_STAGING_PREFIX.rst
+++ b/Help/variable/CMAKE_STAGING_PREFIX.rst
@@ -5,10 +5,10 @@ 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
+The ``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
+``CMAKE_STAGING_PREFIX``, the matching path fragments are replaced
with the :variable:`CMAKE_INSTALL_PREFIX`.
diff --git a/Help/variable/CMAKE_TASKING_TOOLSET.rst b/Help/variable/CMAKE_TASKING_TOOLSET.rst
index 6bd1479..53b2c09 100644
--- a/Help/variable/CMAKE_TASKING_TOOLSET.rst
+++ b/Help/variable/CMAKE_TASKING_TOOLSET.rst
@@ -14,7 +14,7 @@ the compiler features correctly. If no toolset is specified,
Due to the different versioning schemes, the compiler version
(:variable:`CMAKE_<LANG>_COMPILER_VERSION`) depends on the toolset and
architecture in use. If projects can be built with multiple toolsets or
-architectures, the specified :variable:`CMAKE_TASKING_TOOLSET` and the
+architectures, the specified ``CMAKE_TASKING_TOOLSET`` and the
automatically determined :variable:`CMAKE_<LANG>_COMPILER_ARCHITECTURE_ID`
must be taken into account when comparing against the
:variable:`CMAKE_<LANG>_COMPILER_VERSION`.
diff --git a/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER.rst b/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER.rst
new file mode 100644
index 0000000..f86ed7c
--- /dev/null
+++ b/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER.rst
@@ -0,0 +1,14 @@
+CMAKE_VS_VERSION_BUILD_NUMBER
+-----------------------------
+
+.. versionadded:: 3.26
+
+Visual Studio version.
+
+:ref:`Visual Studio Generators` for VS 2017 and above set this
+variable to the Visual Studio version build number in the format
+``<major>.<minor>.<date>.<build>``.
+
+.. include:: CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt
+
+See also the :variable:`CMAKE_GENERATOR_INSTANCE` variable.
diff --git a/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt b/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt
new file mode 100644
index 0000000..6bdede7
--- /dev/null
+++ b/Help/variable/CMAKE_VS_VERSION_BUILD_NUMBER_COMPONENTS.txt
@@ -0,0 +1,18 @@
+The components are:
+
+``<major>.<minor>``
+
+ The VS major and minor version numbers.
+ These are the same as the release version numbers.
+
+``<date>``
+
+ A build date in the format ``MMMDD``, where ``MMM`` is a month index
+ since an epoch used by Microsoft, and ``DD`` is a day in that month.
+
+``<build>``
+
+ A build index on the day represented by ``<date>``.
+
+The build number is reported by ``vswhere`` as ``installationVersion``.
+For example, VS 16.11.10 has build number ``16.11.32126.315``.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
index d9f136c..f1a1977 100644
--- a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
@@ -5,7 +5,7 @@ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM
Override the :ref:`Windows 10 SDK Maximum Version for VS 2015` and beyond.
-The :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM` variable may
+The ``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.
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst b/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst
index cd65ae3..b8ea1e9 100644
--- a/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst
+++ b/Help/variable/CTEST_CUSTOM_ERROR_EXCEPTION.rst
@@ -2,6 +2,6 @@ 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.
+error messages in build outputs by the :command:`ctest_build` command.
.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst b/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst
index 558f5e5..e8f4ad4 100644
--- a/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst
+++ b/Help/variable/CTEST_CUSTOM_ERROR_MATCH.rst
@@ -2,6 +2,6 @@ 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.
+build outputs by the :command:`ctest_build` 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
index 614859b..31c99e7 100644
--- a/Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst
+++ b/Help/variable/CTEST_CUSTOM_ERROR_POST_CONTEXT.rst
@@ -2,6 +2,6 @@ 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.
+:command:`ctest_build` 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
index 74dc47a..ae03a5c 100644
--- a/Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst
+++ b/Help/variable/CTEST_CUSTOM_ERROR_PRE_CONTEXT.rst
@@ -2,6 +2,6 @@ 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.
+the :command:`ctest_build` command. The default is 10.
.. include:: CTEST_CUSTOM_XXX.txt
diff --git a/Help/variable/GHSMULTI.rst b/Help/variable/GHSMULTI.rst
index 3daef5d..7a90b84 100644
--- a/Help/variable/GHSMULTI.rst
+++ b/Help/variable/GHSMULTI.rst
@@ -6,4 +6,4 @@ GHSMULTI
``1`` when using :generator:`Green Hills MULTI` generator.
Also, Set to ``1`` when the target system is a Green Hills platform
-(i.e. When CMAKE_SYSTEM_NAME is ``GHS-MULTI``).
+(i.e. When :variable:`CMAKE_SYSTEM_NAME` is ``GHS-MULTI``).
diff --git a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
index aea1be8..9158631 100644
--- a/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
+++ b/Help/variable/LINK_LIBRARY_PREDEFINED_FEATURES.txt
@@ -49,14 +49,14 @@
* ``[/path/to/]FwName.framework/Versions/*/FwName[suffix]``
Note that CMake recognizes and automatically handles framework targets,
- even without using the ``$<LINK_LIBRARY:FRAMEWORK,...>`` expression.
+ even without using the :genex:`$<LINK_LIBRARY:FRAMEWORK,...>` expression.
The generator expression can still be used with a CMake target if the
project wants to be explicit about it, but it is not required to do so.
The linker command line may have some differences between using the
generator expression or not, but the final result should be the same.
On the other hand, if a file path is given, CMake will recognize some paths
automatically, but not all cases. The project may want to use
- ``$<LINK_LIBRARY:FRAMEWORK,...>`` for file paths so that the expected
+ :genex:`$<LINK_LIBRARY:FRAMEWORK,...>` for file paths so that the expected
behavior is clear.
.. versionadded:: 3.25
diff --git a/Help/variable/PackageName_ROOT.rst b/Help/variable/PackageName_ROOT.rst
index 98ba20e..6b17be3 100644
--- a/Help/variable/PackageName_ROOT.rst
+++ b/Help/variable/PackageName_ROOT.rst
@@ -5,10 +5,10 @@
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`.
+``<PackageName>`` is the (case-preserved) 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.
diff --git a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
index 46b8b2a..aeac0d9 100644
--- a/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
+++ b/Modules/BasicConfigVersion-AnyNewerVersion.cmake.in
@@ -29,20 +29,4 @@ else()
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()
+@CVF_ARCH_INDEPENDENT_CHECK@
diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in
index c8d2695..8dac2af 100644
--- a/Modules/BasicConfigVersion-ExactVersion.cmake.in
+++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in
@@ -69,20 +69,4 @@ 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()
+@CVF_ARCH_INDEPENDENT_CHECK@
diff --git a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
index cf73f60..85a0355 100644
--- a/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
+++ b/Modules/BasicConfigVersion-SameMajorVersion.cmake.in
@@ -51,20 +51,4 @@ else()
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()
+@CVF_ARCH_INDEPENDENT_CHECK@
diff --git a/Modules/BasicConfigVersion-SameMinorVersion.cmake.in b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
index ef21df6..87c4930 100644
--- a/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
+++ b/Modules/BasicConfigVersion-SameMinorVersion.cmake.in
@@ -71,20 +71,4 @@ else()
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()
+@CVF_ARCH_INDEPENDENT_CHECK@
diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake
index 0beff04..5307901 100644
--- a/Modules/BundleUtilities.cmake
+++ b/Modules/BundleUtilities.cmake
@@ -870,10 +870,6 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs)
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})
@@ -903,6 +899,9 @@ function(fixup_bundle_item resolved_embedded_item exepath dirs)
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}")
+ if(BU_CHMOD_BUNDLE_ITEMS)
+ execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
+ endif()
execute_process(COMMAND ${cmd} RESULT_VARIABLE install_name_tool_result)
if(NOT install_name_tool_result EQUAL 0)
string(REPLACE ";" "' '" msg "'${cmd}'")
diff --git a/Modules/CMakeASM_MARMASMInformation.cmake b/Modules/CMakeASM_MARMASMInformation.cmake
new file mode 100644
index 0000000..2026c17
--- /dev/null
+++ b/Modules/CMakeASM_MARMASMInformation.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.
+
+
+# support for the MS ARM assembler, marmasm and marmasm64
+
+set(ASM_DIALECT "_MARMASM")
+
+set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> <SOURCE>")
+
+# The ASM_MARMASM 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 "")
+
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_Embedded "-g")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_ProgramDatabase "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue "")
+
+include(CMakeASMInformation)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeCCompilerABI.c b/Modules/CMakeCCompilerABI.c
index f0ee21a..63596be 100644
--- a/Modules/CMakeCCompilerABI.c
+++ b/Modules/CMakeCCompilerABI.c
@@ -9,7 +9,8 @@
#include "CMakeCompilerABI.h"
#ifdef __CLASSIC_C__
-int main(argc, argv) int argc;
+int main(argc, argv)
+int argc;
char* argv[];
#else
int main(int argc, char* argv[])
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
index bda1d71..cd978d5 100644
--- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -12,6 +12,7 @@ macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
FAIL_REGEX "switch .* is no longer supported" # GNU
FAIL_REGEX "unknown .*option" # Clang
FAIL_REGEX "optimization flag .* not supported" # Clang
+ FAIL_REGEX "argument unused during compilation: .*" # Clang
FAIL_REGEX "unknown argument ignored" # Clang (cl)
FAIL_REGEX "ignoring unknown option" # MSVC, Intel
FAIL_REGEX "warning D9002" # MSVC, any lang
diff --git a/Modules/CMakeDetermineASM_MARMASMCompiler.cmake b/Modules/CMakeDetermineASM_MARMASMCompiler.cmake
new file mode 100644
index 0000000..26714dd
--- /dev/null
+++ b/Modules/CMakeDetermineASM_MARMASMCompiler.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 ARM assembler (marmasm or marmasm64)
+
+set(ASM_DIALECT "_MARMASM")
+
+# if we are using the 64bit cl compiler, assume we also want the 64bit assembler
+if(";${CMAKE_VS_PLATFORM_NAME};${CMAKE_C_COMPILER_ARCHITECTURE_ID};${CMAKE_CXX_COMPILER_ARCHITECTURE_ID};"
+ MATCHES ";(ARM64);")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT armasm64)
+else()
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT armasm)
+endif()
+
+include(CMakeDetermineASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index f43b17b..53c5f78 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -520,10 +520,10 @@ elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
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")
+ message(CONFIGURE_LOG
+ "Parsed CUDA nvcc implicit link information:\n${_nvcc_log}\n${log}\n\n")
else()
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_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()
@@ -576,10 +576,10 @@ if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
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")
+ message(CONFIGURE_LOG
+ "Parsed CUDA nvcc include information:\n${_nvcc_log}\n${log}\n\n")
else()
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n")
endif()
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index 053effa..4169734 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -82,8 +82,6 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
# 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")
@@ -126,8 +124,8 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
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")
+ message(CONFIGURE_LOG
+ "Parsed ${lang} implicit include dir info: 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.
@@ -151,8 +149,8 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
"${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
COMPUTE_IMPLICIT_OBJECTS implicit_objs
LANGUAGE ${lang})
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Parsed ${lang} implicit link information from above output:\n${log}\n\n")
+ message(CONFIGURE_LOG
+ "Parsed ${lang} implicit link information:\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
@@ -195,8 +193,6 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
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
index 73c775a..41e0e1a 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -2,6 +2,8 @@
# file Copyright.txt or https://cmake.org/licensing for details.
macro(__determine_compiler_id_test testflags_var userflags_var)
+ set(_CMAKE_${lang}_COMPILER_ID_LOG "")
+
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}")
@@ -11,6 +13,9 @@ macro(__determine_compiler_id_test testflags_var userflags_var)
CMAKE_DETERMINE_COMPILER_ID_CHECK("${lang}" "${CMAKE_${lang}_COMPILER_ID_DIR}/${file}" "${src}")
endforeach()
endif()
+
+ message(CONFIGURE_LOG "${_CMAKE_${lang}_COMPILER_ID_LOG}")
+ unset(_CMAKE_${lang}_COMPILER_ID_LOG)
endmacro()
# Function to compile a source file to identify the compiler. This is
@@ -85,8 +90,6 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
# 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
@@ -116,7 +119,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
RESULT_VARIABLE result
TIMEOUT 10
)
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
"${output}\n"
)
@@ -140,7 +143,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
RESULT_VARIABLE result
TIMEOUT 10
)
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" -version\n"
"${output}\n"
)
@@ -160,7 +163,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
RESULT_VARIABLE result
TIMEOUT 10
)
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Running the ${lang} compiler: \"${CMAKE_${lang}_COMPILER}\" --version\n"
"${output}\n"
)
@@ -216,6 +219,9 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
AND MSVC_${lang}_ARCHITECTURE_ID)
foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX(${lang} "${userflags}")
+ if(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX)
+ break()
+ endif()
endforeach()
else()
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "")
@@ -243,8 +249,12 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
else()
set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
endif()
- elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xFujitsuClang")
+ elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xGNU"
+ OR "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xAppleClang"
+ OR "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xFujitsuClang")
set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "GNU")
+ elseif("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
+ set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC")
else()
set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "")
endif()
@@ -720,7 +730,7 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
OR CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line"
)
# Compilation failed.
- string(APPEND _CMAKE_DETERMINE_COMPILER_ID_BUILD_MSG
+ set(MSG
"Compiling the ${lang} compiler identification source file \"${src}\" failed.
${COMPILER_DESCRIPTION}
The output was:
@@ -730,14 +740,16 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
")
# Log the output unless we recognize it as a known-bad case.
if(NOT CMAKE_${lang}_COMPILER_ID_OUTPUT MATCHES "warning #5117: Bad # preprocessor line")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG "${MSG}")
endif()
+ string(APPEND _CMAKE_DETERMINE_COMPILER_ID_BUILD_MSG "${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 "${_CMAKE_DETERMINE_COMPILER_ID_BUILD_MSG}")
- else()
+ elseif(CMAKE_${lang}_COMPILER_ID_REQUIRE_SUCCESS)
# Build up the outputs for compiler detection attempts so that users
# can see all set of flags tried, instead of just last
set(_CMAKE_DETERMINE_COMPILER_ID_BUILD_MSG "${_CMAKE_DETERMINE_COMPILER_ID_BUILD_MSG}" PARENT_SCOPE)
@@ -748,7 +760,7 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
set(COMPILER_${lang}_PRODUCED_OUTPUT)
else()
# Compilation succeeded.
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG
"Compiling the ${lang} compiler identification source file \"${src}\" succeeded.
${COMPILER_DESCRIPTION}
The output was:
@@ -777,7 +789,7 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
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
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG
"Compilation of the ${lang} compiler identification source \""
"${src}\" produced \"${file}\"\n\n")
endif()
@@ -785,7 +797,7 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
if(NOT COMPILER_${lang}_PRODUCED_FILES)
# No executable was found.
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG
"Compilation of the ${lang} compiler identification source \""
"${src}\" did not produce an executable in \""
"${CMAKE_${lang}_COMPILER_ID_DIR}\".\n\n")
@@ -797,6 +809,7 @@ ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
# 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)
+ set(_CMAKE_${lang}_COMPILER_ID_LOG "${_CMAKE_${lang}_COMPILER_ID_LOG}" PARENT_SCOPE)
endfunction()
@@ -990,15 +1003,16 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
# 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")
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG
+ "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}, found in:\n"
+ " ${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")
+ string(APPEND _CMAKE_${lang}_COMPILER_ID_LOG
+ "The ${lang} compiler identification could not be found in:\n"
+ " ${file}\n\n")
endif()
+ set(_CMAKE_${lang}_COMPILER_ID_LOG "${_CMAKE_${lang}_COMPILER_ID_LOG}" PARENT_SCOPE)
endif()
# try to figure out the executable format: ELF, COFF, Mach-O
@@ -1085,7 +1099,7 @@ function(CMAKE_DETERMINE_COMPILER_ID_VENDOR lang userflags)
)
if("${output}" MATCHES "${regex}")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
"matched \"${regex}\":\n${output}")
set(CMAKE_${lang}_COMPILER_ID "${vendor}" PARENT_SCOPE)
@@ -1094,11 +1108,11 @@ function(CMAKE_DETERMINE_COMPILER_ID_VENDOR lang userflags)
break()
else()
if("${result}" MATCHES "timeout")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_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
+ message(CONFIGURE_LOG
"Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
"did not match \"${regex}\":\n${output}")
endif()
@@ -1129,9 +1143,12 @@ function(CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX lang userflags)
RESULT_VARIABLE res
ENCODING AUTO # cl prints in console output code page
)
- if(res EQUAL 0 AND "${out}" MATCHES "(^|\n)([^:\n]*:[^:\n]*:[ \t]*)")
+ string(REPLACE "\n" "\n " msg " ${out}")
+ if(res EQUAL 0 AND "${out}" MATCHES "(^|\n)([^:\n][^:\n]+:[^:\n]*[^: \n][^: \n]:?[ \t]+)[A-Za-z]:\\\\")
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ string(APPEND msg "\nFound prefix \"${CMAKE_MATCH_2}\"")
else()
set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "" PARENT_SCOPE)
endif()
+ message(CONFIGURE_LOG "Detecting ${lang} compiler /showIncludes prefix:\n${msg}\n")
endfunction()
diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake
index 087c0f6..8cbaf70 100644
--- a/Modules/CMakeDetermineFortranCompiler.cmake
+++ b/Modules/CMakeDetermineFortranCompiler.cmake
@@ -187,11 +187,11 @@ if(NOT CMAKE_Fortran_COMPILER_ID_RUN)
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
+ message(CONFIGURE_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
+ message(CONFIGURE_LOG
"Determining if the Fortran compiler is GNU failed with "
"the following output:\n${CMAKE_COMPILER_OUTPUT}\n\n")
endif()
@@ -284,6 +284,9 @@ if(MSVC_Fortran_ARCHITECTURE_ID)
set(SET_MSVC_Fortran_ARCHITECTURE_ID
"set(MSVC_Fortran_ARCHITECTURE_ID ${MSVC_Fortran_ARCHITECTURE_ID})")
endif()
+if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC")
+ set(CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS ";cuf;CUF")
+endif()
# configure variables set in this file for fast reload later on
configure_file(${CMAKE_ROOT}/Modules/CMakeFortranCompiler.cmake.in
${CMAKE_PLATFORM_INFO_DIR}/CMakeFortranCompiler.cmake
diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake
index 2c2c2ac..d4dcc62 100644
--- a/Modules/CMakeDetermineSystem.cmake
+++ b/Modules/CMakeDetermineSystem.cmake
@@ -33,20 +33,32 @@
# find out on which system cmake runs
if(CMAKE_HOST_UNIX)
- find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin )
+ find_program(CMAKE_UNAME NAMES uname PATHS /bin /usr/bin /usr/local/bin)
if(CMAKE_UNAME)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "AIX")
- exec_program(${CMAKE_UNAME} ARGS -v OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MAJOR_VERSION)
- exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MINOR_VERSION)
+ execute_process(COMMAND ${CMAKE_UNAME} -v
+ OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MAJOR_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+ execute_process(COMMAND ${CMAKE_UNAME} -r
+ OUTPUT_VARIABLE _CMAKE_HOST_SYSTEM_MINOR_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
set(CMAKE_HOST_SYSTEM_VERSION "${_CMAKE_HOST_SYSTEM_MAJOR_VERSION}.${_CMAKE_HOST_SYSTEM_MINOR_VERSION}")
unset(_CMAKE_HOST_SYSTEM_MAJOR_VERSION)
unset(_CMAKE_HOST_SYSTEM_MINOR_VERSION)
else()
- exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
+ execute_process(COMMAND ${CMAKE_UNAME} -r
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
endif()
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|MSYS.*|^GNU$|Android")
- exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
- RETURN_VALUE val)
+ execute_process(COMMAND ${CMAKE_UNAME} -m
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RESULT_VARIABLE val
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
# If we are running on Apple Silicon, honor CMAKE_APPLE_SILICON_PROCESSOR.
if(DEFINED CMAKE_APPLE_SILICON_PROCESSOR)
@@ -74,8 +86,11 @@ if(CMAKE_HOST_UNIX)
if(_CMAKE_APPLE_SILICON_PROCESSOR)
set(CMAKE_HOST_SYSTEM_PROCESSOR "${_CMAKE_APPLE_SILICON_PROCESSOR}")
else()
- exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
- RETURN_VALUE val)
+ execute_process(COMMAND ${CMAKE_UNAME} -m
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RESULT_VARIABLE val
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
endif()
unset(_CMAKE_APPLE_SILICON_PROCESSOR)
if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
@@ -83,14 +98,23 @@ if(CMAKE_HOST_UNIX)
set(CMAKE_HOST_SYSTEM_PROCESSOR "powerpc")
endif()
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD")
- exec_program(arch ARGS -s OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
- RETURN_VALUE val)
+ execute_process(COMMAND arch -s
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RESULT_VARIABLE val
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
else()
- exec_program(${CMAKE_UNAME} ARGS -p OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
- RETURN_VALUE val)
+ execute_process(COMMAND ${CMAKE_UNAME} -p
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RESULT_VARIABLE val
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
if("${val}" GREATER 0)
- exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
- RETURN_VALUE val)
+ execute_process(COMMAND ${CMAKE_UNAME} -m
+ OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+ RESULT_VARIABLE val
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
endif()
endif()
# check the return of the last uname -m or -p
@@ -172,13 +196,14 @@ endif()
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")
+ message(CONFIGURE_LOG
+ "The target system is: ${CMAKE_SYSTEM_NAME} - ${CMAKE_SYSTEM_VERSION} - ${CMAKE_SYSTEM_PROCESSOR}\n"
+ "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")
+ message(CONFIGURE_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,
diff --git a/Modules/CMakeFindDependencyMacro.cmake b/Modules/CMakeFindDependencyMacro.cmake
index bcdfbeb..2c04abe 100644
--- a/Modules/CMakeFindDependencyMacro.cmake
+++ b/Modules/CMakeFindDependencyMacro.cmake
@@ -3,7 +3,7 @@
#[=======================================================================[.rst:
CMakeFindDependencyMacro
--------------------------
+------------------------
.. command:: find_dependency
@@ -28,36 +28,70 @@ CMakeFindDependencyMacro
The call to :command:`return` makes this macro unsuitable to call
from :ref:`Find Modules`.
+
+Package Dependency Search Optimizations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If ``find_dependency`` is called with arguments identical to a previous
+call in the same directory, perhaps due to diamond-shaped package
+dependencies, the underlying call to :command:`find_package` is optimized
+out. This optimization is important to support large package dependency
+graphs while avoiding a combinatorial explosion of repeated searches.
+However, the heuristic cannot account for ambient variables that
+affect package behavior, such as ``<PackageName>_USE_STATIC_LIBS``,
+offered by some packages. Therefore package configuration files should
+avoid setting such variables before their calls to ``find_dependency``.
+
+.. versionchanged:: 3.15
+ Previously, the underlying call to :command:`find_package` was always
+ optimized out if the package had already been found. CMake 3.15
+ removed the optimization to support cases in which ``find_dependency``
+ call arguments request different components.
+
+.. versionchanged:: 3.26
+ The pre-3.15 optimization was restored, but with the above-described
+ heuristic to account for varying ``find_dependency`` call arguments.
+
#]=======================================================================]
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()
+ string(SHA256 cmake_fd_call_hash "${dep};${ARGN};${${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED}")
+ if(_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND)
+ unset(cmake_fd_call_hash)
+ else()
+ list(APPEND _CMAKE_${dep}_HASH_STACK ${cmake_fd_call_hash})
+ 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
- )
+ get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
+ _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
+ )
- find_package(${dep} ${ARGN}
- ${cmake_fd_quiet_arg}
- ${cmake_fd_required_arg}
- )
+ find_package(${dep} ${ARGN}
+ ${cmake_fd_quiet_arg}
+ ${cmake_fd_required_arg}
+ )
+ list(POP_BACK _CMAKE_${dep}_HASH_STACK cmake_fd_call_hash)
+ set("_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND" "${${dep}_FOUND}")
- if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
- set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
- endif()
+ 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()
+ unset(cmake_fd_alreadyTransitive)
+ unset(cmake_fd_call_hash)
+ unset(cmake_fd_quiet_arg)
+ unset(cmake_fd_required_arg)
+ 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()
endif()
- set(cmake_fd_required_arg)
- set(cmake_fd_quiet_arg)
endmacro()
diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in
index 97f891e..f52ad02 100644
--- a/Modules/CMakeFortranCompiler.cmake.in
+++ b/Modules/CMakeFortranCompiler.cmake.in
@@ -25,7 +25,7 @@ set(CMAKE_Fortran_COMPILER_ENV_VAR "FC")
set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 @CMAKE_Fortran_COMPILER_SUPPORTS_F90@)
set(CMAKE_Fortran_COMPILER_ID_RUN 1)
-set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95)
+set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95@CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS@)
set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
set(CMAKE_Fortran_LINKER_PREFERENCE 20)
if(UNIX)
diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake
index e2925dc..77c1780 100644
--- a/Modules/CMakeGenericSystem.cmake
+++ b/Modules/CMakeGenericSystem.cmake
@@ -30,12 +30,18 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
# LINK_LIBRARY_OVERRIDE_<LIBRARY> target properties
set(CMAKE_LINK_LIBRARY_USING_DEFAULT_SUPPORTED TRUE)
-set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
-set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
+if(NOT DEFINED CMAKE_AUTOGEN_ORIGIN_DEPENDS)
+ set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
+endif()
+if(NOT DEFINED CMAKE_AUTOMOC_COMPILER_PREDEFINES)
+ set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
+endif()
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")
+if(NOT DEFINED CMAKE_AUTOMOC_MACRO_NAMES)
+ set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE" "Q_NAMESPACE_EXPORT")
+endif()
# basically all general purpose OSs support shared libs
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
diff --git a/Modules/CMakeMSYSFindMake.cmake b/Modules/CMakeMSYSFindMake.cmake
index 33b02c9..96fdb37 100644
--- a/Modules/CMakeMSYSFindMake.cmake
+++ b/Modules/CMakeMSYSFindMake.cmake
@@ -3,8 +3,13 @@
find_program(CMAKE_MAKE_PROGRAM make
+ REGISTRY_VIEW 32
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)
+ # Typical install path for 32-bit MSYS2 (https://repo.msys2.org/distrib/msys2-i686-latest.sfx.exe)
+ "C:/msys32/usr"
+ # Typical install path for MINGW32 (https://sourceforge.net/projects/mingw)
+ "C:/mingw/msys"
+ # Git for Windows 32-bit (https://gitforwindows.org/)
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GitForWindows;InstallPath]/usr")
+
mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/CMakePackageConfigHelpers.cmake b/Modules/CMakePackageConfigHelpers.cmake
index 6f5702a..1dc850a 100644
--- a/Modules/CMakePackageConfigHelpers.cmake
+++ b/Modules/CMakePackageConfigHelpers.cmake
@@ -200,14 +200,16 @@ Example using both :command:`configure_package_config_file` and
.. code-block:: cmake
- set(INCLUDE_INSTALL_DIR include/ ... CACHE )
- set(LIB_INSTALL_DIR lib/ ... CACHE )
- set(SYSCONFIG_INSTALL_DIR etc/foo/ ... CACHE )
+ include(GNUInstallDirs)
+ set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/Foo
+ CACHE PATH "Location of header files" )
+ set(SYSCONFIG_INSTALL_DIR ${CMAKE_INSTALL_SYSCONFDIR}/foo
+ CACHE PATH "Location of configuration files" )
#...
include(CMakePackageConfigHelpers)
configure_package_config_file(FooConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
- INSTALL_DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo
PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
@@ -215,7 +217,7 @@ Example using both :command:`configure_package_config_file` and
COMPATIBILITY SameMajorVersion )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
- DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake )
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo )
``FooConfig.cmake.in``:
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 16726d2..a75dfce 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -17,19 +17,20 @@ if(CMAKE_Swift_COMPILER_ID)
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)
+
+# FIXME: Move compiler- and platform-specific flags to the above-included modules.
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS"
+ OR CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS")
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)
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS"
+ OR CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS")
set(CMAKE_EXECUTABLE_RUNTIME_Swift_FLAG_SEP "")
set(CMAKE_SHARED_LIBRARY_RUNTIME_Swift_FLAG_SEP "")
else()
@@ -65,10 +66,22 @@ set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -libc MD)
set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -libc MTd)
set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -libc MDd)
-set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g")
-set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
-set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
-set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+if(CMAKE_GENERATOR STREQUAL "Xcode")
+ # Xcode has a separate Xcode project option (SWIFT_COMPILATION_MODE) used to set
+ # whether compiling with whole-module optimizations or incrementally. Setting
+ # these options here will have no effect when compiling with the built-in driver,
+ # and will explode violently, leaving build products in the source directory, when
+ # using the old swift driver.
+ set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g")
+ set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O")
+ set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+ set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize")
+else()
+ set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g -incremental")
+ set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O -wmo")
+ set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g -wmo")
+ set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize -wmo")
+endif()
if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
if(NOT DEFINED CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG)
@@ -91,7 +104,7 @@ if(NOT CMAKE_Swift_NUM_THREADS MATCHES "^[0-9]+$")
endif()
if(NOT CMAKE_Swift_CREATE_SHARED_LIBRARY)
- set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
+ set(CMAKE_Swift_CREATE_SHARED_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS} <LINK_LIBRARIES>")
endif()
if(NOT CMAKE_Swift_CREATE_SHARED_MODULE)
@@ -99,11 +112,15 @@ if(NOT CMAKE_Swift_CREATE_SHARED_MODULE)
endif()
if(NOT CMAKE_Swift_LINK_EXECUTABLE)
- set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ set(CMAKE_Swift_LINK_EXECUTABLE "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-executable -o <TARGET> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+endif()
+
+if(NOT CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS)
+ set(CMAKE_Swift_LINK_EXECUTABLE_WITH_EXPORTS "${CMAKE_Swift_LINK_EXECUTABLE} -emit-module -emit-module-path <SWIFT_MODULE> ${CMAKE_Swift_IMPLIB_LINKER_FLAGS}")
endif()
if(NOT CMAKE_Swift_CREATE_STATIC_LIBRARY)
- set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -output-file-map <SWIFT_OUTPUT_FILE_MAP> -incremental -j ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
+ set(CMAKE_Swift_CREATE_STATIC_LIBRARY "<CMAKE_Swift_COMPILER> -j ${CMAKE_Swift_NUM_THREADS} -num-threads ${CMAKE_Swift_NUM_THREADS} -emit-library -static -o <TARGET> -module-name <SWIFT_MODULE_NAME> -module-link-name <SWIFT_LIBRARY_NAME> -emit-module -emit-module-path <SWIFT_MODULE> -emit-dependencies <DEFINES> <FLAGS> <INCLUDES> <SWIFT_SOURCES> <LINK_FLAGS> <LINK_LIBRARIES>")
set(CMAKE_Swift_ARCHIVE_CREATE "<CMAKE_AR> crs <TARGET> <OBJECTS>")
set(CMAKE_Swift_ARCHIVE_FINISH "")
diff --git a/Modules/CMakeTestASM_MARMASMCompiler.cmake b/Modules/CMakeTestASM_MARMASMCompiler.cmake
new file mode 100644
index 0000000..a6de04c
--- /dev/null
+++ b/Modules/CMakeTestASM_MARMASMCompiler.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_MARMASM "compiler" (should be marmasm or marmasm64)
+# 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 "_MARMASM")
+include(CMakeTestASMCompiler)
+set(ASM_DIALECT)
diff --git a/Modules/CMakeTestCCompiler.cmake b/Modules/CMakeTestCCompiler.cmake
index a706767..58726db 100644
--- a/Modules/CMakeTestCCompiler.cmake
+++ b/Modules/CMakeTestCCompiler.cmake
@@ -63,9 +63,6 @@ if(NOT CMAKE_C_COMPILER_WORKS)
__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 "
@@ -73,9 +70,6 @@ if(NOT CMAKE_C_COMPILER_WORKS)
"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
diff --git a/Modules/CMakeTestCSharpCompiler.cmake b/Modules/CMakeTestCSharpCompiler.cmake
index 1c9e249..9f4b99f 100644
--- a/Modules/CMakeTestCSharpCompiler.cmake
+++ b/Modules/CMakeTestCSharpCompiler.cmake
@@ -44,9 +44,6 @@ 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 "
@@ -55,9 +52,6 @@ if(NOT CMAKE_CSharp_COMPILER_WORKS)
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.
diff --git a/Modules/CMakeTestCUDACompiler.cmake b/Modules/CMakeTestCUDACompiler.cmake
index f2fa6ea..5779e4b 100644
--- a/Modules/CMakeTestCUDACompiler.cmake
+++ b/Modules/CMakeTestCUDACompiler.cmake
@@ -60,7 +60,7 @@ if(CMAKE_CUDA_ABI_COMPILED)
set(_CUDA_ARCHS_STATUS "")
endif()
string(REPLACE "\n" "\n " _CUDA_ARCHS_OUTPUT " ${_CUDA_ARCHS_OUTPUT}")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_LOG
"Detecting the CUDA native architecture(s) failed with "
"the following output:\n${_CUDA_ARCHS_OUTPUT}\n\n")
endif()
@@ -96,9 +96,6 @@ if(NOT 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 "
@@ -106,9 +103,6 @@ if(NOT CMAKE_CUDA_COMPILER_WORKS)
"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
diff --git a/Modules/CMakeTestCXXCompiler.cmake b/Modules/CMakeTestCXXCompiler.cmake
index fa4016a..e640ff9 100644
--- a/Modules/CMakeTestCXXCompiler.cmake
+++ b/Modules/CMakeTestCXXCompiler.cmake
@@ -56,9 +56,6 @@ if(NOT CMAKE_CXX_COMPILER_WORKS)
__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 C++ 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 "
@@ -66,9 +63,6 @@ if(NOT CMAKE_CXX_COMPILER_WORKS)
"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_CXX_COMPILER_OUTPUT}\n\n")
endif()
# Try to identify the compiler features
diff --git a/Modules/CMakeTestFortranCompiler.cmake b/Modules/CMakeTestFortranCompiler.cmake
index e6d1f6d..1baa18d 100644
--- a/Modules/CMakeTestFortranCompiler.cmake
+++ b/Modules/CMakeTestFortranCompiler.cmake
@@ -55,9 +55,6 @@ if(NOT 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 "
@@ -65,9 +62,6 @@ if(NOT CMAKE_Fortran_COMPILER_WORKS)
"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.
@@ -84,15 +78,9 @@ if(NOT DEFINED CMAKE_Fortran_COMPILER_SUPPORTS_F90)
unset(__TestCompiler_testFortranCompilerF90Source)
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)
diff --git a/Modules/CMakeTestHIPCompiler.cmake b/Modules/CMakeTestHIPCompiler.cmake
index 1da0ae4..686f055 100644
--- a/Modules/CMakeTestHIPCompiler.cmake
+++ b/Modules/CMakeTestHIPCompiler.cmake
@@ -59,9 +59,6 @@ if(NOT CMAKE_HIP_COMPILER_WORKS)
__TestCompiler_restoreTryCompileTargetType()
if(NOT CMAKE_HIP_COMPILER_WORKS)
PrintTestCompilerResult(CHECK_FAIL "broken")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Determining if the HIP compiler works failed with "
- "the following output:\n${__CMAKE_HIP_COMPILER_OUTPUT}\n\n")
string(REPLACE "\n" "\n " _output "${__CMAKE_HIP_COMPILER_OUTPUT}")
message(FATAL_ERROR "The HIP compiler\n \"${CMAKE_HIP_COMPILER}\"\n"
"is not able to compile a simple test program.\nIt fails "
@@ -69,9 +66,6 @@ if(NOT CMAKE_HIP_COMPILER_WORKS)
"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 HIP compiler works passed with "
- "the following output:\n${__CMAKE_HIP_COMPILER_OUTPUT}\n\n")
endif()
set(CMAKE_HIP_FLAGS "${__CMAKE_HIP_FLAGS}")
diff --git a/Modules/CMakeTestOBJCCompiler.cmake b/Modules/CMakeTestOBJCCompiler.cmake
index bbc90a7..a36180b 100644
--- a/Modules/CMakeTestOBJCCompiler.cmake
+++ b/Modules/CMakeTestOBJCCompiler.cmake
@@ -60,9 +60,6 @@ if(NOT CMAKE_OBJC_COMPILER_WORKS)
__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 "
@@ -70,9 +67,6 @@ if(NOT CMAKE_OBJC_COMPILER_WORKS)
"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
diff --git a/Modules/CMakeTestOBJCXXCompiler.cmake b/Modules/CMakeTestOBJCXXCompiler.cmake
index aceb939..f7935c7 100644
--- a/Modules/CMakeTestOBJCXXCompiler.cmake
+++ b/Modules/CMakeTestOBJCXXCompiler.cmake
@@ -59,9 +59,6 @@ if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
__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 "
@@ -69,9 +66,6 @@ if(NOT CMAKE_OBJCXX_COMPILER_WORKS)
"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
diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake
index 88a864c..c7df912 100644
--- a/Modules/CMakeTestSwiftCompiler.cmake
+++ b/Modules/CMakeTestSwiftCompiler.cmake
@@ -36,9 +36,6 @@ 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 "
@@ -47,9 +44,6 @@ if(NOT CMAKE_Swift_COMPILER_WORKS)
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.
diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake
index 7c3ad6b..f9cf33f 100644
--- a/Modules/CPack.cmake
+++ b/Modules/CPack.cmake
@@ -262,7 +262,7 @@ installers. The most commonly-used variables are:
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
+ installed executable :program:`ccmake`. Not all CPack generators use it (at least
NSIS, and WIX do).
.. variable:: CPACK_STRIP_FILES
diff --git a/Modules/CUDA/architectures.cmake b/Modules/CUDA/architectures.cmake
index d646920..7d6a6e0 100644
--- a/Modules/CUDA/architectures.cmake
+++ b/Modules/CUDA/architectures.cmake
@@ -17,7 +17,7 @@ if(CMAKE_CUDA_COMPILER_TOOLKIT_VERSION VERSION_GREATER_EQUAL 9.0)
endif()
list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 20 21)
- list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 20 21)
+ list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 20)
endif()
if(CMAKE_CUDA_COMPILER_TOOLKIT_VERSION VERSION_GREATER_EQUAL 10.0
@@ -51,6 +51,12 @@ if(CMAKE_CUDA_COMPILER_TOOLKIT_VERSION VERSION_GREATER_EQUAL 11.8
list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 90)
endif()
+if(CMAKE_CUDA_COMPILER_TOOLKIT_VERSION VERSION_GREATER_EQUAL 12.0
+ AND (NOT CMAKE_CUDA_COMPILER_ID STREQUAL "Clang"))
+ list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 35 37)
+ list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 35)
+endif()
+
# only generate jit code for the newest arch for all/all-major
list(POP_BACK CMAKE_CUDA_ARCHITECTURES_ALL _latest_arch)
list(TRANSFORM CMAKE_CUDA_ARCHITECTURES_ALL APPEND "-real")
diff --git a/Modules/CheckFortranFunctionExists.cmake b/Modules/CheckFortranFunctionExists.cmake
index 7e3a7ee..4e5a246 100644
--- a/Modules/CheckFortranFunctionExists.cmake
+++ b/Modules/CheckFortranFunctionExists.cmake
@@ -70,21 +70,14 @@ macro(CHECK_FORTRAN_FUNCTION_EXISTS FUNCTION VARIABLE)
SOURCE_FROM_VAR testFortranCompiler.f __CheckFunction_testFortranCompilerSource
${CHECK_FUNCTION_EXISTS_ADD_LINK_OPTIONS}
${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}
- OUTPUT_VARIABLE OUTPUT
)
unset(__CheckFunction_testFortranCompilerSource)
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
index e134329..8dcc1d5 100644
--- a/Modules/CheckFortranSourceCompiles.cmake
+++ b/Modules/CheckFortranSourceCompiles.cmake
@@ -19,18 +19,22 @@ Check if given Fortran source compiles and links into an executable.
)
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:
+ source file and linked as an executable. The ``<code>`` must be a Fortran
+ ``program``.
.. code-block:: cmake
- check_fortran_source_compiles("character :: b; error stop b; end" F2018ESTOPOK SRC_EXT F90)
+ check_fortran_source_compiles("program test
+ error stop
+ end program"
+ HAVE_ERROR_STOP
+ 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.
+ :command:`check_fortran_source_runs` command to run the compiled code.
The result will be stored in the internal cache
variable ``<resultVar>``, with a boolean true value for success and boolean
diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake
index 28f713f..985c765 100644
--- a/Modules/CheckFortranSourceRuns.cmake
+++ b/Modules/CheckFortranSourceRuns.cmake
@@ -18,12 +18,16 @@ subsequently be run.
[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:
+ file, linked as an executable and then run. The ``<code>`` must be a Fortran
+ ``program``.
.. code-block:: cmake
- check_fortran_source_runs("real :: x[*]; call co_sum(x); end" F2018coarrayOK)
+ check_fortran_source_runs("program test
+ real :: x[*]
+ call co_sum(x)
+ end program"
+ HAVE_COARRAY)
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
diff --git a/Modules/CheckFunctionExists.cmake b/Modules/CheckFunctionExists.cmake
index 60f0184..e2939ed 100644
--- a/Modules/CheckFunctionExists.cmake
+++ b/Modules/CheckFunctionExists.cmake
@@ -95,7 +95,7 @@ macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE)
${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})
@@ -103,17 +103,11 @@ macro(CHECK_FUNCTION_EXISTS FUNCTION VARIABLE)
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
index 9108e34..de682b7 100644
--- a/Modules/CheckIPOSupported.cmake
+++ b/Modules/CheckIPOSupported.cmake
@@ -150,9 +150,6 @@ macro(_ipo_run_language_check language)
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)
diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake
index 4cba91b..5771307 100644
--- a/Modules/CheckIncludeFile.cmake
+++ b/Modules/CheckIncludeFile.cmake
@@ -100,7 +100,7 @@ macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE)
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)
@@ -113,19 +113,11 @@ macro(CHECK_INCLUDE_FILE INCLUDE VARIABLE)
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/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake
index f6af036..d27b485 100644
--- a/Modules/CheckIncludeFileCXX.cmake
+++ b/Modules/CheckIncludeFileCXX.cmake
@@ -99,7 +99,7 @@ macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE)
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)
@@ -112,19 +112,11 @@ macro(CHECK_INCLUDE_FILE_CXX INCLUDE VARIABLE)
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
index 8fc6921..2f50c61 100644
--- a/Modules/CheckIncludeFiles.cmake
+++ b/Modules/CheckIncludeFiles.cmake
@@ -142,7 +142,7 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE)
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})
@@ -150,19 +150,11 @@ macro(CHECK_INCLUDE_FILES INCLUDE VARIABLE)
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${_src_content}\n")
endif()
endif()
endmacro()
diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake
index 52f707c..2e56a19 100644
--- a/Modules/CheckLanguage.cmake
+++ b/Modules/CheckLanguage.cmake
@@ -90,14 +90,14 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
)
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
+ message(CONFIGURE_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
+ message(CONFIGURE_LOG
"${_desc} failed with the following output:\n"
"${_cl_output}\n")
endif()
diff --git a/Modules/CheckLibraryExists.cmake b/Modules/CheckLibraryExists.cmake
index 56424ac..5f1a914 100644
--- a/Modules/CheckLibraryExists.cmake
+++ b/Modules/CheckLibraryExists.cmake
@@ -76,7 +76,7 @@ macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE)
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}
-DLINK_DIRECTORIES:STRING=${LOCATION}
- OUTPUT_VARIABLE OUTPUT)
+ )
unset(_cle_source)
if(${VARIABLE})
@@ -84,19 +84,11 @@ macro(CHECK_LIBRARY_EXISTS LIBRARY FUNCTION LOCATION VARIABLE)
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/CheckPrototypeDefinition.cmake b/Modules/CheckPrototypeDefinition.cmake
index 12f4e86..3d53b93 100644
--- a/Modules/CheckPrototypeDefinition.cmake
+++ b/Modules/CheckPrototypeDefinition.cmake
@@ -104,24 +104,18 @@ function(check_prototype_definition _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIAB
${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()
diff --git a/Modules/CheckSourceCompiles.cmake b/Modules/CheckSourceCompiles.cmake
index ad74c3c..9788798 100644
--- a/Modules/CheckSourceCompiles.cmake
+++ b/Modules/CheckSourceCompiles.cmake
@@ -19,17 +19,34 @@ Check if given source compiles and links into an executable.
[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.
+ file for the requested language and linked as an executable. 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 compiler 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 ``<code>`` must contain a valid main program. For example:
+
+ .. code-block:: cmake
+
+ check_source_compiles(C
+ "#include <stdlib.h>
+ #include <stdnoreturn.h>
+ noreturn void f(){ exit(0); }
+ int main(void) { f(); return 1; }"
+ HAVE_NORETURN)
+
+ check_source_compiles(Fortran
+ "program test
+ error stop
+ end program"
+ HAVE_ERROR_STOP)
+
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()``:
@@ -73,7 +90,6 @@ Check if given source compiles and links into an executable.
#]=======================================================================]
-
include_guard(GLOBAL)
include(Internal/CheckSourceCompiles)
diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake
index 8f1cf01..e2fa579 100644
--- a/Modules/CheckSourceRuns.cmake
+++ b/Modules/CheckSourceRuns.cmake
@@ -20,22 +20,40 @@ subsequently be run.
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).
+ 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
+ a 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 ``<code>`` must contain a valid main program. For example:
+
+ .. code-block:: cmake
+
+ check_source_runs(C
+ "#include <stdlib.h>
+ #include <stdnoreturn.h>
+ noreturn void f(){ exit(0); }
+ int main(void) { f(); return 1; }"
+ HAVE_NORETURN)
+
+ check_source_runs(Fortran
+ "program test
+ real :: x[*]
+ call co_sum(x)
+ end program"
+ HAVE_COARRAY)
+
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()``:
+ variables prior to calling ``check_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
+ :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``.
diff --git a/Modules/CheckSymbolExists.cmake b/Modules/CheckSymbolExists.cmake
index 722d50f..c4a1574 100644
--- a/Modules/CheckSymbolExists.cmake
+++ b/Modules/CheckSymbolExists.cmake
@@ -150,27 +150,17 @@ int main(int argc, char** argv)
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"
- "${_CSE_SOURCE}\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"
- "${_CSE_SOURCE}\n")
endif()
unset(_CSE_SOURCE)
endif()
diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake
index e09b7c8..579d189 100644
--- a/Modules/CheckTypeSize.cmake
+++ b/Modules/CheckTypeSize.cmake
@@ -152,7 +152,6 @@ function(__check_type_size_impl type var map builtin language)
CMAKE_FLAGS
"-DCOMPILE_DEFINITIONS:STRING=${CMAKE_REQUIRED_FLAGS}"
"-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}"
- OUTPUT_VARIABLE output
COPY_FILE ${bin}
)
@@ -203,16 +202,12 @@ function(__check_type_size_impl type var map builtin language)
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(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Determining size of ${type} failed with the following output:\n${output}\n${src}:\n${src_content}\n\n")
set(${var} "" CACHE INTERNAL "CHECK_TYPE_SIZE: ${type} unknown")
file(REMOVE ${map})
endif()
diff --git a/Modules/CheckVariableExists.cmake b/Modules/CheckVariableExists.cmake
index 5dc3441..3a7a431 100644
--- a/Modules/CheckVariableExists.cmake
+++ b/Modules/CheckVariableExists.cmake
@@ -67,23 +67,17 @@ macro(CHECK_VARIABLE_EXISTS VAR VARIABLE)
${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/Clang-FindBinUtils.cmake b/Modules/Compiler/Clang-FindBinUtils.cmake
index 125ae78..daf0371 100644
--- a/Modules/Compiler/Clang-FindBinUtils.cmake
+++ b/Modules/Compiler/Clang-FindBinUtils.cmake
@@ -43,3 +43,14 @@ find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
DOC "Generate index for LLVM archive"
)
mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB)
+
+# clang-scan-deps
+find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CLANG_SCAN_DEPS NAMES
+ "${_CMAKE_TOOLCHAIN_PREFIX}clang-scan-deps-${__version_x_y}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}clang-scan-deps-${__version_x}"
+ "${_CMAKE_TOOLCHAIN_PREFIX}clang-scan-deps"
+ HINTS ${__clang_hints}
+ NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH
+ DOC "`clang-scan-deps` dependency scanner"
+)
+mark_as_advanced(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_CLANG_SCAN_DEPS)
diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake
index 257402a..6c544fd 100644
--- a/Modules/Compiler/Clang.cmake
+++ b/Modules/Compiler/Clang.cmake
@@ -44,7 +44,7 @@ else()
set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
- if(CMAKE_${lang}_COMPILER_TARGET)
+ if(CMAKE_${lang}_COMPILER_TARGET AND "${lang}" STREQUAL "CXX")
if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.4.0)
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-target" "${CMAKE_${lang}_COMPILER_TARGET}")
else()
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
index 48639cd..5930e37 100644
--- a/Modules/Compiler/GNU.cmake
+++ b/Modules/Compiler/GNU.cmake
@@ -121,13 +121,15 @@ macro(__compiler_gnu lang)
)
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)
+ if("${lang}" STREQUAL "CXX")
+ 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")
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)
diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake
index 53456f5..7908f96 100644
--- a/Modules/Compiler/IAR.cmake
+++ b/Modules/Compiler/IAR.cmake
@@ -8,54 +8,48 @@
#
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")
+macro(__compiler_iar_common lang)
+ if (${lang} MATCHES "^(C|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_MINSIZEREL_INIT " -Ohz -DNDEBUG")
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -Oh -r -DNDEBUG")
endif()
+ set(CMAKE_${lang}_RESPONSE_FILE_FLAG "-f ")
+ set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "-f ")
+
+ set(CMAKE_${lang}_ARCHIVE_FINISH "")
+endmacro()
+
+macro(__compiler_iar_ilink lang)
+ set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+ set(CMAKE_${lang}_OUTPUT_EXTENSION ".o")
+
+ __compiler_iar_common(${lang})
+
set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> --silent <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> --create <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> <TARGET> --replace <LINK_FLAGS> <OBJECTS>")
- set(CMAKE_${lang}_ARCHIVE_FINISH "")
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()
+ __compiler_iar_common(${lang})
set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> -S <OBJECTS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> -o <TARGET>")
set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_${lang}_ARCHIVE_APPEND "")
- set(CMAKE_${lang}_ARCHIVE_FINISH "")
set(CMAKE_LIBRARY_PATH_FLAG "-I")
endmacro()
diff --git a/Modules/Compiler/IBMClang.cmake b/Modules/Compiler/IBMClang.cmake
index 9ed7658..a9d760f 100644
--- a/Modules/Compiler/IBMClang.cmake
+++ b/Modules/Compiler/IBMClang.cmake
@@ -36,7 +36,7 @@ macro(__compiler_ibmclang lang)
set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
- if(CMAKE_${lang}_COMPILER_TARGET)
+ if(CMAKE_${lang}_COMPILER_TARGET AND "${lang}" STREQUAL "CXX")
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
endif()
@@ -66,7 +66,9 @@ macro(__compiler_ibmclang lang)
"\"${__ranlib}\" <TARGET>"
)
- list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+ if("${lang}" STREQUAL "CXX")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
+ endif()
set(CMAKE_PCH_EXTENSION .pch)
diff --git a/Modules/Compiler/Intel.cmake b/Modules/Compiler/Intel.cmake
index 642e58a..317cfc7 100644
--- a/Modules/Compiler/Intel.cmake
+++ b/Modules/Compiler/Intel.cmake
@@ -30,13 +30,15 @@ else()
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)
+ if("${lang}" STREQUAL "CXX")
+ 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")
endif()
- list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-QdM" "-P" "-Za" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
if("x${lang}" STREQUAL "xFortran")
set(CMAKE_${lang}_COMPILE_OPTIONS_WARNING_AS_ERROR "-warn" "errors")
diff --git a/Modules/Compiler/IntelLLVM-C.cmake b/Modules/Compiler/IntelLLVM-C.cmake
index d7346f6..3a81154 100644
--- a/Modules/Compiler/IntelLLVM-C.cmake
+++ b/Modules/Compiler/IntelLLVM-C.cmake
@@ -41,6 +41,9 @@ if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+
+ set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c2x")
+ set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu2x")
else()
# clang-cl doesn't have any of these
set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
@@ -54,6 +57,9 @@ else()
set(CMAKE_C17_STANDARD_COMPILE_OPTION "")
set(CMAKE_C17_EXTENSION_COMPILE_OPTION "")
+
+ set(CMAKE_C23_STANDARD_COMPILE_OPTION "")
+ set(CMAKE_C23_EXTENSION_COMPILE_OPTION "")
endif()
__compiler_check_default_language_standard(C 2020 17)
diff --git a/Modules/Compiler/IntelLLVM-CXX.cmake b/Modules/Compiler/IntelLLVM-CXX.cmake
index 4d3f5a1..45b723f 100644
--- a/Modules/Compiler/IntelLLVM-CXX.cmake
+++ b/Modules/Compiler/IntelLLVM-CXX.cmake
@@ -46,6 +46,9 @@ if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")
+
+ set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-std=c++2b")
+ set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-std=gnu++2b")
else()
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
@@ -53,14 +56,17 @@ else()
set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
- set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-Qstd=c++14")
- set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-Qstd=c++14")
+ 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_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")
- set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-Qstd=c++20")
- set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-Qstd=c++20")
+ set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-Qstd:c++2b")
+ set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-Qstd:c++2b")
endif()
__compiler_check_default_language_standard(CXX 2020 14)
diff --git a/Modules/Compiler/IntelLLVM.cmake b/Modules/Compiler/IntelLLVM.cmake
index 30de1a9..e256c8f 100644
--- a/Modules/Compiler/IntelLLVM.cmake
+++ b/Modules/Compiler/IntelLLVM.cmake
@@ -80,15 +80,17 @@ else()
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}")
+ if("${lang}" STREQUAL "CXX")
+ 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()
endif()
if("x${lang}" STREQUAL "xFortran")
diff --git a/Modules/Compiler/LCC-C-DetermineCompiler.cmake b/Modules/Compiler/LCC-C-DetermineCompiler.cmake
index 2ce92fe..3f46210 100644
--- a/Modules/Compiler/LCC-C-DetermineCompiler.cmake
+++ b/Modules/Compiler/LCC-C-DetermineCompiler.cmake
@@ -2,10 +2,8 @@
set(_compiler_id_pp_test "defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))")
set(_compiler_id_version_compute "
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(1)
-# if defined(__LCC__)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__LCC__- 100)
-# endif
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__LCC__ / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__LCC__ % 100)
# if defined(__LCC_MINOR__)
# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__LCC_MINOR__)
# endif
diff --git a/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake b/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake
index 2ce92fe..3f46210 100644
--- a/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake
+++ b/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake
@@ -2,10 +2,8 @@
set(_compiler_id_pp_test "defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))")
set(_compiler_id_version_compute "
-# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(1)
-# if defined(__LCC__)
-# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__LCC__- 100)
-# endif
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__LCC__ / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__LCC__ % 100)
# if defined(__LCC_MINOR__)
# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__LCC_MINOR__)
# endif
diff --git a/Modules/Compiler/LCC.cmake b/Modules/Compiler/LCC.cmake
index bdee9a6..f8c2084 100644
--- a/Modules/Compiler/LCC.cmake
+++ b/Modules/Compiler/LCC.cmake
@@ -76,13 +76,15 @@ macro(__compiler_lcc lang)
"\"${CMAKE_${lang}_COMPILER_RANLIB}\" <TARGET>"
)
- 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)
+ if("${lang}" STREQUAL "CXX")
+ 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")
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)
diff --git a/Modules/Compiler/LLVMFlang-Fortran.cmake b/Modules/Compiler/LLVMFlang-Fortran.cmake
index 651bf51..9e72b06 100644
--- a/Modules/Compiler/LLVMFlang-Fortran.cmake
+++ b/Modules/Compiler/LLVMFlang-Fortran.cmake
@@ -13,3 +13,4 @@ set(CMAKE_Fortran_MODDIR_FLAG "-module-dir")
set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
index a65fd2c..b946cfd 100644
--- a/Modules/Compiler/NAG-Fortran.cmake
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -14,7 +14,7 @@ if(NOT CMAKE_Fortran_COMPILER_WORKS AND NOT CMAKE_Fortran_COMPILER_FORCED)
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
+ message(CONFIGURE_LOG
"Detecting NAG Fortran directory with -dryrun found\n"
" object: ${_nag_obj}\n"
" directory: ${_nag_dir}\n"
@@ -22,7 +22,7 @@ if(NOT CMAKE_Fortran_COMPILER_WORKS AND NOT CMAKE_Fortran_COMPILER_FORCED)
"from output:\n${_dryrun}\n\n")
message(CHECK_PASS "${_nag_dir}")
else()
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_LOG
"Detecting NAG Fortran directory with -dryrun failed:\n${_dryrun}\n\n")
message(CHECK_FAIL "failed")
endif()
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
index 670e0ca..0823954 100644
--- a/Modules/Compiler/NVIDIA-CUDA.cmake
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -70,7 +70,7 @@ if(NOT "x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
endif()
set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS -shared)
-set(CMAKE_INCLUDE_SYSTEM_FLAG_CUDA -isystem=)
+set(CMAKE_INCLUDE_SYSTEM_FLAG_CUDA "-isystem ")
if (CMAKE_CUDA_SIMULATE_ID STREQUAL "GNU")
set(CMAKE_CUDA_LINKER_WRAPPER_FLAG "-Wl,")
diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake
index 7fbfd10..b720dc1 100644
--- a/Modules/Compiler/QCC.cmake
+++ b/Modules/Compiler/QCC.cmake
@@ -22,13 +22,15 @@ macro(__compiler_qcc lang)
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)
+ if("${lang}" STREQUAL "CXX")
+ 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")
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)
diff --git a/Modules/Compiler/Tasking.cmake b/Modules/Compiler/Tasking.cmake
index 5bf066e..82622fa 100644
--- a/Modules/Compiler/Tasking.cmake
+++ b/Modules/Compiler/Tasking.cmake
@@ -43,12 +43,14 @@ macro(__compiler_tasking lang)
set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -cs <SOURCE> -o <ASSEMBLY_SOURCE>")
set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -Ep <SOURCE> > <PREPROCESSED_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)
+ if("${lang}" STREQUAL "CXX")
+ 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 "-Ep" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
endif()
- list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-Ep" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
endmacro()
diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake
index 189374b..6826c7b 100644
--- a/Modules/ExternalData.cmake
+++ b/Modules/ExternalData.cmake
@@ -945,7 +945,7 @@ function(_ExternalData_link_or_copy src dst)
file(CREATE_LINK "${tgt}" "${tmp}" RESULT result COPY_ON_ERROR SYMBOLIC)
else()
# Create a copy.
- file(COPY_FILE "${src}" "${tmp}" RESULT result)
+ file(COPY_FILE "${src}" "${tmp}" RESULT result INPUT_MAY_BE_RECENT)
endif()
if(result)
file(REMOVE "${tmp}")
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 9306ce6..b34a35b 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -525,9 +525,9 @@ External Project Definition
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
+ The specified arguments are passed to the :program:`cmake` command line.
+ They can be any argument the :program:`cmake` command understands, not just
+ cache values defined by ``-D...`` arguments (see also
:manual:`CMake Options <cmake(1)>`).
.. versionadded:: 3.3
@@ -611,9 +611,9 @@ External Project Definition
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.
+ :option:`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
@@ -637,8 +637,11 @@ External Project Definition
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`.
+ builds. This may also be required to explicitly declare dependencies
+ when using the :generator:`Ninja` generator.
+ These ultimately get passed through as ``BYPRODUCTS`` to the
+ build step's own underlying call to :command:`add_custom_command`, which
+ has additional documentation.
**Install Step Options:**
If the configure step assumed the external project uses CMake as its build
@@ -661,6 +664,17 @@ External Project Definition
supported). Passing an empty string as the ``<cmd>`` makes the install
step do nothing.
+ ``INSTALL_BYPRODUCTS <file>...``
+ .. versionadded:: 3.26
+
+ Specifies files that will be generated by the install command but which
+ might or might not have their modification time updated by subsequent
+ installs. This may also be required to explicitly declare dependencies
+ when using the :generator:`Ninja` generator.
+ These ultimately get passed through as ``BYPRODUCTS`` to the
+ install step's own underlying call to :command:`add_custom_command`, which
+ has additional documentation.
+
.. note::
If the :envvar:`CMAKE_INSTALL_MODE` environment variable is set when the
main project is built, it will only have an effect if the following
@@ -943,9 +957,12 @@ control needed to implement such step-level capabilities.
.. 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
+ not have their modification time updated by subsequent builds.
+ This may also be required to explicitly declare dependencies
+ when using the :generator:`Ninja` generator. 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.
+ :command:`add_custom_command` used to implement the custom step internally,
+ which has additional documentation.
``ALWAYS <bool>``
When enabled, this option specifies that the custom step should always be
@@ -3641,7 +3658,7 @@ function(_ep_extract_configure_command var name)
)
endif()
- list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
+ list(APPEND cmd -S "<SOURCE_DIR><SOURCE_SUBDIR>" -B "<BINARY_DIR>")
endif()
set("${var}" "${cmd}" PARENT_SCOPE)
@@ -3845,6 +3862,11 @@ function(_ep_add_install_command name)
set(always 0)
endif()
+ get_property(install_byproducts
+ TARGET ${name}
+ PROPERTY _EP_INSTALL_BYPRODUCTS
+ )
+
set(__cmdQuoted)
foreach(__item IN LISTS cmd)
string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -3853,6 +3875,7 @@ function(_ep_add_install_command name)
ExternalProject_Add_Step(${name} install
INDEPENDENT FALSE
COMMAND ${__cmdQuoted}
+ BYPRODUCTS \${install_byproducts}
WORKING_DIRECTORY \${binary_dir}
DEPENDEES build
ALWAYS \${always}
@@ -4080,6 +4103,7 @@ function(ExternalProject_Add name)
# Install step options
#
INSTALL_COMMAND
+ INSTALL_BYPRODUCTS
#
# Test step options
#
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 047603c..8afb9bc 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -762,7 +762,7 @@ frameworks are available to the main build:
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
- GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
+ GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
)
# After the following call, the CMake targets defined by googletest and
@@ -796,7 +796,7 @@ to the declared details and leaving
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
- GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
+ GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
FIND_PACKAGE_ARGS
)
@@ -831,7 +831,7 @@ details:
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
- GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
+ GIT_TAG 605a34765aa5d5ecbf476b4598a862ada971b0cc # v3.0.1
OVERRIDE_FIND_PACKAGE
)
@@ -928,9 +928,8 @@ it depends directly on projects ``projB`` and ``projC``. Both ``projB`` and
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
+ :caption: *projA*
include(FetchContent)
FetchContent_Declare(
@@ -957,9 +956,9 @@ that all five projects are available on a company git server. The
# Order is important, see notes in the discussion further below
FetchContent_MakeAvailable(projD projB projC)
-*projB*:
.. code-block:: cmake
+ :caption: *projB*
include(FetchContent)
FetchContent_Declare(
@@ -975,9 +974,9 @@ that all five projects are available on a company git server. The
FetchContent_MakeAvailable(projD projE)
-*projC*:
.. code-block:: cmake
+ :caption: *projC*
include(FetchContent)
FetchContent_Declare(
@@ -1052,7 +1051,7 @@ 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.
+place, even the very first time that :program:`cmake` is run in the build directory.
Populating Content In CMake Script Mode
"""""""""""""""""""""""""""""""""""""""
@@ -1063,9 +1062,8 @@ firmware tarball using CMake's :manual:`script mode <cmake(1)>`. The call to
unpacked firmware will be placed in a ``firmware`` directory below the
current working directory.
-*getFirmware.cmake*:
-
.. code-block:: cmake
+ :caption: :file:`getFirmware.cmake`
# NOTE: Intended to be run in script mode with cmake -P
include(FetchContent)
diff --git a/Modules/FindBZip2.cmake b/Modules/FindBZip2.cmake
index 355c4bb..326e700 100644
--- a/Modules/FindBZip2.cmake
+++ b/Modules/FindBZip2.cmake
@@ -29,8 +29,11 @@ This module defines the following variables:
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
+``BZIP2_VERSION``
+ .. versionadded:: 3.26
+ the version of BZip2 found.
+
+ See also legacy variable ``BZIP2_VERSION_STRING``.
Cache variables
^^^^^^^^^^^^^^^
@@ -39,6 +42,17 @@ The following cache variables may also be set:
``BZIP2_INCLUDE_DIR``
the BZip2 include directory
+
+Legacy Variables
+^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``BZIP2_VERSION_STRING``
+ the version of BZip2 found.
+
+ .. versionchanged:: 3.26
+ Superseded by ``BZIP2_VERSION``.
#]=======================================================================]
set(_BZIP2_PATHS PATHS
@@ -60,12 +74,13 @@ 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}")
+ set(BZIP2_VERSION ${BZIP2_VERSION_STRING})
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)
+ VERSION_VAR BZIP2_VERSION)
if (BZIP2_FOUND)
set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 8adb3bf..c3b6bc3 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -380,6 +380,24 @@ Targets Created:
- ``CUDA::nvrtc``
+.. versionadded:: 3.26
+
+ - ``CUDA::nvrtc_builtins``
+ - ``CUDA::nvrtc_static`` starting in CUDA 11.5
+ - ``CUDA::nvrtc_builtins_static`` starting in CUDA 11.5
+
+.. _`cuda_toolkit_nvjitlink`:
+
+nvJitLink
+"""""""""
+
+The `nvJItLink <https://docs.nvidia.com/cuda/>`_ (Runtime LTO Linking) library.
+
+Targets Created:
+
+- ``CUDA::nvJitLink`` starting in CUDA 12.0
+- ``CUDA::nvJitLink_static`` starting in CUDA 12.0
+
.. _`cuda_toolkit_nvml`:
nvidia-ML
@@ -783,32 +801,35 @@ endif()
if(CMAKE_CROSSCOMPILING)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
# Support for NVPACK
- set(CUDAToolkit_TARGET_NAME "armv7-linux-androideabi")
+ set(CUDAToolkit_TARGET_NAMES "armv7-linux-androideabi")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
- set(CUDAToolkit_TARGET_NAME "armv7-linux-gnueabihf")
+ set(CUDAToolkit_TARGET_NAMES "armv7-linux-gnueabihf")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
if(ANDROID_ARCH_NAME STREQUAL "arm64")
- set(CUDAToolkit_TARGET_NAME "aarch64-linux-androideabi")
+ set(CUDAToolkit_TARGET_NAMES "aarch64-linux-androideabi")
elseif (CMAKE_SYSTEM_NAME STREQUAL "QNX")
- set(CUDAToolkit_TARGET_NAME "aarch64-qnx")
+ set(CUDAToolkit_TARGET_NAMES "aarch64-qnx")
else()
- set(CUDAToolkit_TARGET_NAME "aarch64-linux")
- endif(ANDROID_ARCH_NAME STREQUAL "arm64")
+ set(CUDAToolkit_TARGET_NAMES "aarch64-linux" "sbsa-linux")
+ endif()
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
- set(CUDAToolkit_TARGET_NAME "x86_64-linux")
+ set(CUDAToolkit_TARGET_NAMES "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()
+ foreach(CUDAToolkit_TARGET_NAME IN LISTS CUDAToolkit_TARGET_NAMES)
+ 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)
+ break()
+ endif()
+ endforeach()
endif()
# If not already set we can simply use the toolkit root or it's a scattered installation.
@@ -831,11 +852,18 @@ elseif(NOT CUDAToolkit_FIND_QUIETLY)
message(STATUS "Unable to find cuda_runtime.h in \"${CUDAToolkit_TARGET_DIR}/include\" for CUDAToolkit_INCLUDE_DIR.")
endif()
-# The NVHPC layout moves math library headers and libraries to a sibling directory.
+# The NVHPC layout moves math library headers and libraries to a sibling directory and it could be nested under
+# the version of the CUDA toolchain
# Create a separate variable so this directory can be selectively added to math targets.
if(NOT EXISTS "${CUDAToolkit_INCLUDE_DIR}/cublas_v2.h")
- set(CUDAToolkit_MATH_INCLUDE_DIR "${CUDAToolkit_TARGET_DIR}/../../math_libs/include")
+ file(REAL_PATH "${CUDAToolkit_TARGET_DIR}" CUDAToolkit_MATH_INCLUDE_DIR)
+ cmake_path(APPEND CUDAToolkit_MATH_INCLUDE_DIR "../../math_libs/")
+ if(EXISTS "${CUDAToolkit_MATH_INCLUDE_DIR}/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/")
+ cmake_path(APPEND CUDAToolkit_MATH_INCLUDE_DIR "${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/")
+ endif()
+ cmake_path(APPEND CUDAToolkit_MATH_INCLUDE_DIR "include")
cmake_path(NORMAL_PATH CUDAToolkit_MATH_INCLUDE_DIR)
+
if(NOT EXISTS "${CUDAToolkit_MATH_INCLUDE_DIR}/cublas_v2.h")
if(NOT CUDAToolkit_FIND_QUIETLY)
message(STATUS "Unable to find cublas_v2.h in either \"${CUDAToolkit_INCLUDE_DIR}\" or \"${CUDAToolkit_MATH_INCLUDE_DIR}\"")
@@ -887,8 +915,25 @@ mark_as_advanced(CUDA_CUDART
if(CUDAToolkit_FOUND)
set(CUDAToolkit_INCLUDE_DIRS ${CUDAToolkit_INCLUDE_DIR})
get_filename_component(CUDAToolkit_LIBRARY_DIR ${CUDA_CUDART} DIRECTORY ABSOLUTE)
+
+ # Build search paths without any symlinks
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}" _cmake_search_dir)
+ set(CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+
+ # Detect we are in a splayed nvhpc toolkit layout and add extra
+ # search paths without symlinks
+ if(CUDAToolkit_LIBRARY_DIR MATCHES ".*/cuda/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64$")
+ # Search location for math_libs/
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}/../../../" _cmake_search_dir)
+ list(APPEND CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+
+ # Search location for extras like cupti
+ file(REAL_PATH "${CUDAToolkit_LIBRARY_DIR}/../" _cmake_search_dir)
+ list(APPEND CUDAToolkit_LIBRARY_SEARCH_DIRS "${_cmake_search_dir}")
+ endif()
endif()
+
#-----------------------------------------------------------------------------
# Construct import targets
if(CUDAToolkit_FOUND)
@@ -900,21 +945,21 @@ if(CUDAToolkit_FOUND)
find_library(CUDA_${lib_name}_LIBRARY
NAMES ${search_names}
- HINTS ${CUDAToolkit_LIBRARY_DIR}
+ HINTS ${CUDAToolkit_LIBRARY_SEARCH_DIRS}
ENV CUDA_PATH
PATH_SUFFIXES nvidia/current lib64 lib/x64 lib
+ # Support NVHPC splayed math library layout
+ math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64
+ math_libs/lib64
${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}
+ HINTS ${CUDAToolkit_LIBRARY_SEARCH_DIRS}
ENV CUDA_PATH
PATH_SUFFIXES lib64/stubs lib/x64/stubs lib/stubs stubs
- # Support NVHPC splayed math library layout
- ../../math_libs/${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}/lib64
- ../../math_libs/lib64
)
mark_as_advanced(CUDA_${lib_name}_LIBRARY)
@@ -1047,16 +1092,19 @@ if(CUDAToolkit_FOUND)
if(CUDAToolkit_CUPTI_INCLUDE_DIR)
_CUDAToolkit_find_and_add_import_lib(cupti
- EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+ EXTRA_PATH_SUFFIXES extras/CUPTI/lib64/
+ extras/CUPTI/lib/
+ ../extras/CUPTI/lib64/
../extras/CUPTI/lib/
EXTRA_INCLUDE_DIRS "${CUDAToolkit_CUPTI_INCLUDE_DIR}")
_CUDAToolkit_find_and_add_import_lib(cupti_static
- EXTRA_PATH_SUFFIXES ../extras/CUPTI/lib64/
+ EXTRA_PATH_SUFFIXES extras/CUPTI/lib64/
+ extras/CUPTI/lib/
+ ../extras/CUPTI/lib64/
../extras/CUPTI/lib/
EXTRA_INCLUDE_DIRS "${CUDAToolkit_CUPTI_INCLUDE_DIR}")
endif()
- _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS cuda_driver)
if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.1.0)
if(NOT TARGET CUDA::nvptxcompiler_static)
_CUDAToolkit_find_and_add_import_lib(nvptxcompiler_static DEPS cuda_driver)
@@ -1066,6 +1114,18 @@ if(CUDAToolkit_FOUND)
endif()
endif()
+ if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 12.0.0)
+ _CUDAToolkit_find_and_add_import_lib(nvJitLink DEPS cuda_driver)
+ _CUDAToolkit_find_and_add_import_lib(nvJitLink_static DEPS cuda_driver)
+ endif()
+
+ _CUDAToolkit_find_and_add_import_lib(nvrtc_builtins DEPS cuda_driver)
+ _CUDAToolkit_find_and_add_import_lib(nvrtc DEPS nvrtc_builtins nvJitLink)
+ if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.5.0)
+ _CUDAToolkit_find_and_add_import_lib(nvrtc_builtins_static ALT nvrtc-builtins_static DEPS cuda_driver)
+ _CUDAToolkit_find_and_add_import_lib(nvrtc_static DEPS nvrtc_builtins_static nvptxcompiler_static nvJitLink_static)
+ endif()
+
_CUDAToolkit_find_and_add_import_lib(nvml ALT nvidia-ml nvml)
if(WIN32)
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index d662a7d..db03c54 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -222,6 +222,10 @@ function(_HDF5_test_regular_compiler_C success version is_parallel)
if(NOT ${success} OR
NOT EXISTS ${scratch_directory}/compiler_has_h5_c)
set(test_file ${scratch_directory}/cmake_hdf5_test.c)
+ # CXX project without C enabled
+ if(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_LOADED)
+ set(test_file ${scratch_directory}/cmake_hdf5_test.cpp)
+ endif()
file(WRITE ${test_file}
"#include <hdf5.h>\n"
"const char* info_ver = \"INFO\" \":\" H5_VERSION;\n"
diff --git a/Modules/FindImageMagick.cmake b/Modules/FindImageMagick.cmake
index d7de0dd..6baf471 100644
--- a/Modules/FindImageMagick.cmake
+++ b/Modules/FindImageMagick.cmake
@@ -5,7 +5,9 @@
FindImageMagick
---------------
-Find ImageMagick binary suite.
+Find ImageMagick, software suite for displaying, converting and
+manipulating raster images.
+
.. versionadded:: 3.9
Added support for ImageMagick 7.
@@ -15,76 +17,92 @@ 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``
- 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.
+There are also components for the following ImageMagick APIs:
+* ``Magick++``: ImageMagick C++ API, if found.
+* ``MagickWand``: ImageMagick MagickWand C API, if found.
+* ``MagickCore``: ImageMagick MagickCore low-level C API, if found.
-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:
-::
+Imported targets
+^^^^^^^^^^^^^^^^
- 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)
+.. versionadded:: 3.26
+This module defines the following :prop_tgt:`IMPORTED` targets:
+``ImageMagick::Magick++``
+ ImageMagick C++ API, if found.
-``ImageMagick_VERSION_STRING`` will not work for old versions like 5.2.3.
+``ImageMagick::MagickWand``
+ ImageMagick MagickWand C API, if found.
-There are also components for the following ImageMagick APIs:
+``ImageMagick::MagickCore``
+ ImageMagick MagickCore low-level C API, if found.
-::
- Magick++
- MagickWand
- MagickCore
+Result Variables
+^^^^^^^^^^^^^^^^
+``ImageMagick_FOUND``
+ TRUE if all components are found.
+``ImageMagick_EXECUTABLE_DIR``
+ Full path to executables directory.
-For these components the following variables are set:
+``ImageMagick_INCLUDE_DIRS``
+ Full paths to all include dirs.
-::
+``ImageMagick_LIBRARIES``
+ Full paths to all libraries.
- 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.
+``ImageMagick_COMPILE_OPTIONS``
+ Compile options of all libraries.
+``ImageMagick_VERSION_STRING``
+ The version of ImageMagick found (since CMake 2.8.8).
+ Will not work for old versions like 5.2.3.
+``ImageMagick_<component>_FOUND``
+ TRUE if <component> is found.
-Example Usages:
+``ImageMagick_<component>_EXECUTABLE``
+ Full path to <component> executable.
-::
+``ImageMagick_<component>_INCLUDE_DIRS``
+ Full path to <component> include dirs.
- 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)
+``ImageMagick_<component>_COMPILE_OPTIONS``
+ .. versionadded:: 3.26
+
+ Compile options of <component>.
+``ImageMagick_<component>_LIBRARIES``
+ Full path to <component> libraries.
-Note that the standard :command:`find_package` features are supported (i.e.,
-``QUIET``, ``REQUIRED``, etc.).
+Example Usage
+^^^^^^^^^^^^^
+
+.. code-block:: cmake
+
+ find_package(ImageMagick COMPONENTS Magick++)
+ target_link_libraries(example PRIVATE ImageMagick::Magick++)
#]=======================================================================]
find_package(PkgConfig QUIET)
@@ -150,6 +168,8 @@ function(FIND_IMAGEMAGICK_API component header)
set(ImageMagick_${component}_INCLUDE_DIRS
${ImageMagick_${component}_INCLUDE_DIRS} PARENT_SCOPE)
+ set(ImageMagick_${component}_COMPILE_OPTIONS ${PC_${component}_CFLAGS_OTHER})
+
# 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)
@@ -159,6 +179,17 @@ function(FIND_IMAGEMAGICK_API component header)
${ImageMagick_${component}_LIBRARY}
)
set(ImageMagick_LIBRARIES ${ImageMagick_LIBRARIES} PARENT_SCOPE)
+
+ list(APPEND ImageMagick_COMPILE_OPTIONS
+ ${ImageMagick_${component}_COMPILE_OPTIONS}
+ )
+ set(ImageMagick_COMPILE_OPTIONS ${ImageMagick_COMPILE_OPTIONS} PARENT_SCOPE)
+
+ add_library(ImageMagick::${component} UNKNOWN IMPORTED)
+ set_target_properties(ImageMagick::${component} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ImageMagick_${component}_INCLUDE_DIRS}"
+ INTERFACE_COMPILE_OPTIONS "${ImageMagick_${component}_COMPILE_OPTIONS}"
+ IMPORTED_LOCATION "${ImageMagick_${component}_LIBRARY}")
endif()
endfunction()
diff --git a/Modules/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
index 9ec8f07..1b3929b 100644
--- a/Modules/FindLibLZMA.cmake
+++ b/Modules/FindLibLZMA.cmake
@@ -33,6 +33,17 @@ This module will set the following variables in your project:
True if lzma_easy_encoder() is found (required).
``LIBLZMA_HAS_LZMA_PRESET``
True if lzma_lzma_preset() is found (required).
+``LIBLZMA_VERSION``
+ .. versionadded:: 3.26
+ the version of LZMA found.
+
+ See also legacy variable ``LIBLZMA_VERSION_STRING``.
+
+Legacy Variables
+^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
``LIBLZMA_VERSION_MAJOR``
The major version of lzma
``LIBLZMA_VERSION_MINOR``
@@ -41,6 +52,10 @@ This module will set the following variables in your project:
The patch version of lzma
``LIBLZMA_VERSION_STRING``
version number as a string (ex: "5.0.3")
+
+ .. versionchanged:: 3.26
+ Superseded by ``LIBLZMA_VERSION``.
+
#]=======================================================================]
find_path(LIBLZMA_INCLUDE_DIR lzma.h )
@@ -61,6 +76,7 @@ if(LIBLZMA_INCLUDE_DIR AND EXISTS "${LIBLZMA_INCLUDE_DIR}/lzma/version.h")
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}")
+ set(LIBLZMA_VERSION ${LIBLZMA_VERSION_STRING})
unset(LIBLZMA_HEADER_CONTENTS)
endif()
@@ -91,7 +107,7 @@ find_package_handle_standard_args(LibLZMA REQUIRED_VARS LIBLZMA_LIBRARY
LIBLZMA_HAS_AUTO_DECODER
LIBLZMA_HAS_EASY_ENCODER
LIBLZMA_HAS_LZMA_PRESET
- VERSION_VAR LIBLZMA_VERSION_STRING
+ VERSION_VAR LIBLZMA_VERSION
)
mark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY )
@@ -101,7 +117,7 @@ if (LIBLZMA_FOUND)
if(NOT TARGET LibLZMA::LibLZMA)
add_library(LibLZMA::LibLZMA UNKNOWN IMPORTED)
set_target_properties(LibLZMA::LibLZMA PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES ${LIBLZMA_INCLUDE_DIR}
+ INTERFACE_INCLUDE_DIRECTORIES "${LIBLZMA_INCLUDE_DIR}"
IMPORTED_LINK_INTERFACE_LANGUAGES C)
if(LIBLZMA_LIBRARY_RELEASE)
diff --git a/Modules/FindMFC.cmake b/Modules/FindMFC.cmake
index 2d5de89..38259c3 100644
--- a/Modules/FindMFC.cmake
+++ b/Modules/FindMFC.cmake
@@ -49,15 +49,9 @@ if(MFC_ATTEMPT_TRY_COMPILE)
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()
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index e15be91..1fbb4f9 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -1259,9 +1259,16 @@ function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY SUPPRE
file(READ "${SRC_DIR}/${MPI_TEST_FILE_NAME}.c" MPI_TEST_SOURCE_CONTENT)
set(MPI_TEST_SOURCE_FILE "${MPI_TEST_FILE_NAME}.c")
endif()
+ if(SUPPRESS_ERRORS)
+ set(maybe_no_log NO_LOG)
+ else()
+ set(maybe_no_log "")
+ endif()
if(RUN_BINARY)
try_run(MPI_RUN_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE} MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
SOURCE_FROM_VAR "${MPI_TEST_SOURCE_FILE}" MPI_TEST_SOURCE_CONTENT
+ ${maybe_no_log}
+ LOG_DESCRIPTION "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE}"
COMPILE_DEFINITIONS ${MPI_TEST_COMPILE_DEFINITIONS}
LINK_LIBRARIES MPI::MPI_${LANG}
RUN_OUTPUT_VARIABLE MPI_RUN_OUTPUT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
@@ -1270,20 +1277,13 @@ function(_MPI_try_staged_settings LANG MPI_TEST_FILE_NAME MODE RUN_BINARY SUPPRE
else()
try_compile(MPI_RESULT_${LANG}_${MPI_TEST_FILE_NAME}_${MODE}
SOURCE_FROM_VAR "${MPI_TEST_SOURCE_FILE}" MPI_TEST_SOURCE_CONTENT
+ ${maybe_no_log}
+ LOG_DESCRIPTION "The MPI test ${MPI_TEST_FILE_NAME} for ${LANG} in mode ${MODE}"
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)
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 07a9adf..0f1e451 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -636,42 +636,26 @@ endfunction()
#]=======================================================================]
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
+ # find_program does not consider script suffix .bat for Matlab mexext.bat on Windows
set(mexext_suffix "")
if(WIN32)
- list(APPEND mexext_suffix ".bat")
+ set(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
+ NAMES mexext mexext${mexext_suffix}
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(NOT Matlab_MEXEXTENSIONS_PROG)
if(MATLAB_FIND_DEBUG)
message(WARNING "[MATLAB] Cannot found mexext program. Matlab root is ${matlab_root}")
endif()
@@ -722,7 +706,6 @@ function(matlab_get_mex_suffix matlab_root mex_suffix)
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()
@@ -1187,7 +1170,7 @@ function(matlab_add_mex)
${${prefix}_UNPARSED_ARGUMENTS})
endif()
- target_include_directories(${${prefix}_NAME} PRIVATE ${Matlab_INCLUDE_DIRS})
+ target_include_directories(${${prefix}_NAME} SYSTEM PRIVATE ${Matlab_INCLUDE_DIRS})
if(NOT ${prefix}_NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES)
if(Matlab_HAS_CPP_API)
@@ -1763,12 +1746,24 @@ else()
set(_matlab_64Build TRUE)
endif()
+
+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(APPLE)
set(_matlab_bin_prefix "mac") # i should be for intel
set(_matlab_bin_suffix_32bits "i")
- if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND Matlab_MEX_EXTENSION MATCHES "a64$")
+ # native Apple Silicon Matlab
set(_matlab_bin_suffix_64bits "a64")
else()
+ # Intel Mac OR Apple Silicon using Rosetta for Matlab
set(_matlab_bin_suffix_64bits "i64")
endif()
elseif(UNIX)
@@ -1812,16 +1807,6 @@ 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()
diff --git a/Modules/FindMsys.cmake b/Modules/FindMsys.cmake
index b4796d2..86597c2 100644
--- a/Modules/FindMsys.cmake
+++ b/Modules/FindMsys.cmake
@@ -19,11 +19,12 @@ if (WIN32)
find_program(MSYS_CMD
NAMES msys2_shell.cmd
PATHS
- "C:/msys64"
+ # Typical install path for MSYS2 (https://repo.msys2.org/distrib/msys2-i686-latest.sfx.exe)
"C:/msys32"
- "C:/MSYS"
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MSYS\\setup;rootdir]"
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Cygnus Solutions\\MSYS\\mounts v2\\/;native]"
+ # Typical install path for MSYS2 (https://repo.msys2.org/distrib/msys2-x86_64-latest.sfx.exe)
+ "C:/msys64"
+ # Git for Windows (https://gitforwindows.org/)
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GitForWindows;InstallPath]"
)
get_filename_component(MSYS_INSTALL_PATH "${MSYS_CMD}" DIRECTORY)
mark_as_advanced(MSYS_CMD)
diff --git a/Modules/FindOpenCL.cmake b/Modules/FindOpenCL.cmake
index 5c7aa22..2b700ff 100644
--- a/Modules/FindOpenCL.cmake
+++ b/Modules/FindOpenCL.cmake
@@ -48,7 +48,7 @@ function(_FIND_OPENCL_VERSION)
foreach(VERSION "3_0" "2_2" "2_1" "2_0" "1_2" "1_1" "1_0")
set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}")
- if(APPLE)
+ if(EXISTS ${OpenCL_INCLUDE_DIR}/Headers/cl.h)
CHECK_SYMBOL_EXISTS(
CL_VERSION_${VERSION}
"${OpenCL_INCLUDE_DIR}/Headers/cl.h"
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 9e24925..68be2d6 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -212,9 +212,14 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}")
endif()
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
+ unset(_includeDirFlags)
+ if(OpenMP_${LANG}_INCLUDE_DIR)
+ set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}")
+ endif()
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
- CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}"
+ LOG_DESCRIPTION "Detecting ${LANG} OpenMP compiler info"
+ CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" ${_includeDirFlags}
LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG}
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
)
@@ -228,9 +233,6 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
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
@@ -240,9 +242,6 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
LANGUAGE ${LANG}
)
- 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")
-
# For LCC we should additionally alanyze -print-search-dirs output
# to check for additional implicit_dirs.
# Note: This won't work if CMP0129 policy is set to OLD!
@@ -255,11 +254,14 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
if("${output_lines}" MATCHES ".*\nlibraries:[ \t]+(.*:)\n.*")
string(REPLACE ":" ";" implicit_dirs_addon "${CMAKE_MATCH_1}")
list(PREPEND OpenMP_${LANG}_IMPLICIT_LINK_DIRS ${implicit_dirs_addon})
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ string(APPEND OpenMP_${LANG}_LOG_VAR
" Extended OpenMP library search paths: [${implicit_dirs}]\n")
endif()
endif()
+ message(CONFIGURE_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)
@@ -312,9 +314,9 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
# default header search path already.
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
+ LOG_DESCRIPTION "Trying ${LANG} OpenMP compiler with '${OpenMP_libomp_LIBRARY}'"
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)
@@ -323,10 +325,10 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
if(OpenMP_${LANG}_INCLUDE_DIR)
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
+ LOG_DESCRIPTION "Trying ${LANG} OpenMP compiler with '${OpenMP_libomp_LIBRARY}' and '${OpenMP_${LANG}_INCLUDE_DIR}'"
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()
@@ -346,9 +348,9 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
if(OpenMP_libomp_LIBRARY)
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
+ LOG_DESCRIPTION "Trying ${LANG} OpenMP compiler with '${OpenMP_libomp_LIBRARY}'"
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)
@@ -356,9 +358,6 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
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)
@@ -419,9 +418,10 @@ function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}")
try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
+ LOG_DESCRIPTION "Detecting ${LANG} OpenMP version"
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")
@@ -429,9 +429,6 @@ function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE)
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()
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
index f66ffcf..4e8374c 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -112,28 +112,85 @@ The following variables may be set to control search behavior:
#]=======================================================================]
macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library)
+ unset(_OpenSSL_extra_static_deps)
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)
+ unset(_OpenSSL_has_dependency_zlib)
+ if(OPENSSL_USE_STATIC_LIBS)
+ set(_OpenSSL_libs "${_OPENSSL_STATIC_LIBRARIES}")
+ set(_OpenSSL_ldflags_other "${_OPENSSL_STATIC_LDFLAGS_OTHER}")
+ else()
+ set(_OpenSSL_libs "${_OPENSSL_LIBRARIES}")
+ set(_OpenSSL_ldflags_other "${_OPENSSL_LDFLAGS_OTHER}")
+ endif()
+ if(_OpenSSL_libs)
+ unset(_OpenSSL_has_dependency_dl)
+ foreach(_OPENSSL_DEP_LIB IN LISTS _OpenSSL_libs)
+ if (_OPENSSL_DEP_LIB STREQUAL "ssl" OR _OPENSSL_DEP_LIB STREQUAL "crypto")
+ # ignoring: these are the targets
+ elseif(_OPENSSL_DEP_LIB STREQUAL CMAKE_DL_LIBS)
+ set(_OpenSSL_has_dependency_dl TRUE)
+ elseif(_OPENSSL_DEP_LIB STREQUAL "z")
+ find_package(ZLIB)
+ set(_OpenSSL_has_dependency_zlib TRUE)
+ else()
+ list(APPEND _OpenSSL_extra_static_deps "${_OPENSSL_DEP_LIB}")
+ endif()
+ endforeach()
+ unset(_OPENSSL_DEP_LIB)
+ else()
+ set(_OpenSSL_has_dependency_dl TRUE)
+ endif()
+ if(_OpenSSL_ldflags_other)
+ unset(_OpenSSL_has_dependency_threads)
+ foreach(_OPENSSL_DEP_LDFLAG IN LISTS _OpenSSL_ldflags_other)
+ if (_OPENSSL_DEP_LDFLAG STREQUAL "-pthread")
+ set(_OpenSSL_has_dependency_threads TRUE)
+ find_package(Threads)
+ endif()
+ endforeach()
+ unset(_OPENSSL_DEP_LDFLAG)
+ else()
+ set(_OpenSSL_has_dependency_threads TRUE)
+ find_package(Threads)
+ endif()
+ unset(_OpenSSL_libs)
+ unset(_OpenSSL_ldflags_other)
else()
set(_OpenSSL_has_dependencies FALSE)
endif()
endmacro()
function(_OpenSSL_add_dependencies libraries_var)
- if(CMAKE_THREAD_LIBS_INIT)
+ if(_OpenSSL_has_dependency_zlib)
+ list(APPEND ${libraries_var} ${ZLIB_LIBRARY})
+ endif()
+ if(_OpenSSL_has_dependency_threads)
list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT})
endif()
- list(APPEND ${libraries_var} ${CMAKE_DL_LIBS})
+ if(_OpenSSL_has_dependency_dl)
+ list(APPEND ${libraries_var} ${CMAKE_DL_LIBS})
+ endif()
+ list(APPEND ${libraries_var} ${_OpenSSL_extra_static_deps})
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} )
+ if(_OpenSSL_has_dependency_zlib)
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ZLIB::ZLIB )
+ endif()
+ if(_OpenSSL_has_dependency_threads)
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ if(_OpenSSL_has_dependency_dl)
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} )
+ endif()
+ if(_OpenSSL_extra_static_deps)
+ set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_OpenSSL_extra_static_deps})
+ endif()
endif()
if(WIN32 AND OPENSSL_USE_STATIC_LIBS)
if(WINCE)
@@ -719,3 +776,7 @@ endif()
unset(_OPENSSL_FIND_PATH_SUFFIX)
unset(_OPENSSL_NAME_POSTFIX)
+unset(_OpenSSL_extra_static_deps)
+unset(_OpenSSL_has_dependency_dl)
+unset(_OpenSSL_has_dependency_threads)
+unset(_OpenSSL_has_dependency_zlib)
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 04f9d8c..fd2eeaa 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -31,6 +31,13 @@ The following components are supported:
* ``Development.Embed``: search for artifacts for Python embedding
developments.
+ .. versionadded:: 3.26
+
+ * ``Development.SABIModule``: search for artifacts for Python module
+ developments using the
+ `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_.
+ This component is available only for version ``3.2`` and upper.
+
* ``NumPy``: search for NumPy include directories.
.. versionadded:: 3.14
@@ -56,7 +63,7 @@ To manage concurrent versions 3 and 2 of Python, use :module:`FindPython3` and
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``
+ with same platform architecture as the one defined by CMake
configuration. This constraint does not apply if only ``Interpreter``
component is specified.
@@ -80,6 +87,12 @@ This module defines the following :ref:`Imported Targets <Imported Targets>`:
Python library for Python module. Target defined if component
``Development.Module`` is found.
+``Python::SABIModule``
+ .. versionadded:: 3.26
+
+ Python library for Python module using the Stable Application Binary
+ Interface. Target defined if component ``Development.SABIModule`` is found.
+
``Python::Python``
Python library for Python embedding. Target defined if component
``Development.Embed`` is found.
@@ -139,12 +152,21 @@ This module will set the following variables in your project
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.
+ Information computed from ``distutils.sysconfig.get_config_var('EXT_SUFFIX')``
+ or ``distutils.sysconfig.get_config_var('SOABI')`` or
+ ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is
+ not available, ``sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``sysconfig.get_config_var('SOABI')`` are used.
+
+``Python_SOSABI``
+ .. versionadded:: 3.26
+
+ Extension suffix for modules using the Stable Application Binary Interface.
+
+ Information computed from ``importlib.machinery.EXTENSION_SUFFIXES`` if the
+ COMPONENT ``Interpreter`` was specified. Otherwise, the extension is ``abi3``
+ except for ``Windows``, ``MSYS`` and ``CYGWIN`` for which this is an empty
+ string.
``Python_Compiler_FOUND``
System has the Python compiler.
@@ -167,6 +189,12 @@ This module will set the following variables in your project
System has the Python development artifacts for Python module.
+``Python_Development.SABIModule_FOUND``
+ .. versionadded:: 3.26
+
+ System has the Python development artifacts for Python module using the
+ Stable Application Binary Interface.
+
``Python_Development.Embed_FOUND``
.. versionadded:: 3.18
@@ -188,6 +216,18 @@ This module will set the following variables in your project
The Python library directories.
``Python_RUNTIME_LIBRARY_DIRS``
The Python runtime library directories.
+``Python_SABI_LIBRARIES``
+ .. versionadded:: 3.26
+
+ The Python libraries for the Stable Application Binary Interface.
+``Python_SABI_LIBRARY_DIRS``
+ .. versionadded:: 3.26
+
+ The Python ``SABI`` library directories.
+``Python_RUNTIME_SABI_LIBRARY_DIRS``
+ .. versionadded:: 3.26
+
+ The Python runtime ``SABI`` library directories.
``Python_VERSION``
Python version.
``Python_VERSION_MAJOR``
@@ -426,6 +466,13 @@ setting the following variables:
variables ``Python_LIBRARIES``, ``Python_LIBRARY_DIRS`` and
``Python_RUNTIME_LIBRARY_DIRS``.
+``Python_SABI_LIBRARY``
+ .. versionadded:: 3.26
+
+ The path to the library for Stable Application Binary Interface. It will be
+ used to compute the variables ``Python_SABI_LIBRARIES``,
+ ``Python_SABI_LIBRARY_DIRS`` and ``Python_RUNTIME_SABI_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``.
@@ -449,7 +496,7 @@ setting the following variables:
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
+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:
@@ -471,10 +518,11 @@ 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::
+when library type is ``MODULE``, to target ``Python::Module`` or
+``Python::SABIModule`` (when ``USE_SABI`` option is specified) and takes care
+of Python module naming rules::
- Python_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+ Python_add_library (<name> [STATIC | SHARED | MODULE [USE_SABI <version>] [WITH_SOABI]]
<source1> [<source2> ...])
If the library type is not specified, ``MODULE`` is assumed.
@@ -482,6 +530,19 @@ 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.
+
+.. versionadded:: 3.26
+ For ``MODULE`` type, if the option ``USE_SABI`` is specified, the
+ preprocessor definition ``Py_LIMITED_API`` will be specified, as ``PRIVATE``,
+ for the target ``<name>`` with the value computed from ``<version>`` argument.
+ The expected format for ``<version>`` is ``major[.minor]``, where each
+ component is a numeric value. If ``minor`` component is specified, the
+ version should be, at least, ``3.2`` which is the version where the
+ `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_
+ was introduced. Specifying only major version ``3`` is equivalent to ``3.2``.
+
+ When option ``WITH_SOABI`` is also specified, the module suffix will include
+ the ``Python3_SOSABI`` value, if any.
#]=======================================================================]
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 37ca38f..f1be0f4 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -16,6 +16,8 @@ cmake_policy (SET CMP0007 NEW)
cmake_policy (SET CMP0012 NEW)
# IN_LIST operator
cmake_policy (SET CMP0057 NEW)
+# foreach loop variable scope
+cmake_policy (SET CMP0124 NEW)
# registry view behavior
cmake_policy (SET CMP0134 NEW)
@@ -55,6 +57,18 @@ macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG)
endmacro()
+function (_PYTHON_ADD_REASON_FAILURE module message)
+ if (_${_PYTHON_PREFIX}_${module}_REASON_FAILURE)
+ string (LENGTH "${_${_PYTHON_PREFIX}_${module}_REASON_FAILURE}" length)
+ math (EXPR length "${length} + 10")
+ string (REPEAT " " ${length} shift)
+ set_property (CACHE _${_PYTHON_PREFIX}_${module}_REASON_FAILURE PROPERTY VALUE "${_${_PYTHON_PREFIX}_${module}_REASON_FAILURE}\n${shift}${message}")
+ else()
+ set_property (CACHE _${_PYTHON_PREFIX}_${module}_REASON_FAILURE PROPERTY VALUE "${message}")
+ endif()
+endfunction()
+
+
function (_PYTHON_MARK_AS_INTERNAL)
foreach (var IN LISTS ARGV)
if (DEFINED CACHE{${var}})
@@ -445,11 +459,18 @@ 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)$")
+ if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI|SOSABI)$")
return()
endif()
- if (_${_PYTHON_PREFIX}_CONFIG)
+ if (NAME STREQUAL "SOSABI")
+ # assume some default
+ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN")
+ set (_values "")
+ else()
+ set (_values "abi${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}")
+ endif()
+ elseif (_${_PYTHON_PREFIX}_CONFIG)
if (NAME STREQUAL "SOABI")
set (config_flag "--extension-suffix")
else()
@@ -471,7 +492,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
list (REMOVE_DUPLICATES _values)
elseif (NAME STREQUAL "SOABI")
# clean-up: remove prefix character and suffix
- if (_values MATCHES "^(\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+ if (_values MATCHES "^(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
set(_values "")
else()
string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
@@ -510,30 +531,64 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
list (REMOVE_DUPLICATES _values)
endif()
elseif (NAME STREQUAL "SOABI")
+ # first step: compute SOABI form EXT_SUFFIX config variable
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 '']))"
+ "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')\nexcept Exception:\n import sysconfig;sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')"
RESULT_VARIABLE _result
- OUTPUT_VARIABLE _soabi
+ OUTPUT_VARIABLE _values
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)$")
+ 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()
+
+ # second step: use SOABI or SO config variables as fallback
+ if (NOT _values)
+ 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('SO') or '']))\nexcept Exception:\n import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') 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()
+ endif()
+ elseif (NAME STREQUAL "SOSABI")
+ execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\nimport re\nimport importlib\nsys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))"
+ RESULT_VARIABLE _result
+ OUTPUT_VARIABLE _values
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_result)
+ unset (_values)
+ else()
+ string (REGEX REPLACE "^\\.(.+)\\.[^.]+$" "\\1" _values "${_values}")
+ endif()
else()
set (config_flag "${NAME}")
if (NAME STREQUAL "CONFIGDIR")
@@ -551,7 +606,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
endif()
endif()
- if (NAME STREQUAL "ABIFLAGS" OR NAME STREQUAL "SOABI")
+ if (NAME STREQUAL "ABIFLAGS" OR NAME STREQUAL "SOABI" OR NAME STREQUAL "SOSABI")
set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
return()
endif()
@@ -576,7 +631,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
endfunction()
function (_PYTHON_GET_VERSION)
- cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;INCLUDE" "PREFIX" "")
+ cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;SABI_LIBRARY;INCLUDE" "PREFIX" "")
unset (${_PGV_PREFIX}VERSION PARENT_SCOPE)
unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE)
@@ -622,6 +677,29 @@ function (_PYTHON_GET_VERSION)
set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
endif()
endif()
+ elseif (_PGV_SABI_LIBRARY)
+ # retrieve version and abi from library name
+ if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ get_filename_component (library_name "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" NAME)
+ # extract version from library name
+ if (library_name MATCHES "python([23])([dmu]*)")
+ set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_2}" PARENT_SCOPE)
+ elseif (library_name MATCHES "pypy([23])-c")
+ set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+ elseif (library_name MATCHES "pypy-c")
+ # try to pick-up a more precise version from the path
+ get_filename_component (library_dir "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+ if (library_dir MATCHES "/pypy([23])\\.([0-9]+)/")
+ set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+ endif()
+ set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+ endif()
+ endif()
else()
if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
# retrieve version from header file
@@ -829,6 +907,7 @@ function (_PYTHON_VALIDATE_INTERPRETER)
endif()
if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ OR "Development.SABIModule" 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
@@ -978,7 +1057,7 @@ function (_PYTHON_VALIDATE_LIBRARY)
if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
# library does not exist anymore
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
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")
@@ -992,7 +1071,7 @@ function (_PYTHON_VALIDATE_LIBRARY)
if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
# incompatible ABI
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
else()
if (_PVL_VERSION OR _PVL_IN_RANGE)
@@ -1001,7 +1080,7 @@ function (_PYTHON_VALIDATE_LIBRARY)
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_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
endif()
endif()
@@ -1011,14 +1090,14 @@ function (_PYTHON_VALIDATE_LIBRARY)
find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE)
if (NOT in_range)
# library has wrong version
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
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_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
endif()
endif()
@@ -1035,6 +1114,51 @@ function (_PYTHON_VALIDATE_LIBRARY)
endfunction()
+function (_PYTHON_VALIDATE_SABI_LIBRARY)
+ if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG)
+ return()
+ endif()
+
+ cmake_parse_arguments (PARSE_ARGV 0 _PVL "CHECK_EXISTS" "" "")
+
+ if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+ # library does not exist anymore
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+ if (WIN32)
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_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 (SABI_LIBRARY PREFIX lib_)
+
+ if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+ # incompatible ABI
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+ else()
+ if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+ # library has wrong major version
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+ endif()
+ endif()
+
+ if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ if (WIN32)
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+ endif()
+ unset (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE CACHE)
+ unset (_${_PYTHON_PREFIX}_RUNTIME_SABI_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()
@@ -1044,7 +1168,7 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR)
if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
# include file does not exist anymore
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
return()
endif()
@@ -1054,14 +1178,14 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR)
if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
# incompatible ABI
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
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_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
endif()
endif()
@@ -1071,14 +1195,14 @@ function (_PYTHON_VALIDATE_INCLUDE_DIR)
find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE)
if (NOT in_range)
# include dir has wrong version
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
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_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
endif()
endif()
@@ -1118,6 +1242,14 @@ endfunction()
function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ if (module STREQUAL "SABIModule"
+ AND "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_LESS "3.2")
+ # Stable API was introduced in version 3.2
+ set (${_PYTHON_PREFIX}_Development.SABIModule_FOUND FALSE PARENT_SCOPE)
+ _python_add_reason_failure ("Development" "SABIModule requires version 3.2 or upper.")
+ return()
+ endif()
+
string(TOUPPER "${module}" id)
set (module_found TRUE)
@@ -1125,6 +1257,10 @@ function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
set (module_found FALSE)
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_SABI_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)
@@ -1171,7 +1307,7 @@ 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)
+foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.SABIModule Development.Embed NumPy)
set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE)
endforeach()
if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)
@@ -1181,6 +1317,7 @@ endif()
unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_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)$")
@@ -1188,10 +1325,16 @@ if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endif()
list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "INCLUDE_DIR")
endif()
+if ("Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+ if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$")
+ list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS "SABI_LIBRARY")
+ endif()
+ list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_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})
+set (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS})
list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
# Set versions to search
@@ -1250,6 +1393,7 @@ else()
endif()
endif()
unset (${_PYTHON_PREFIX}_SOABI)
+unset (${_PYTHON_PREFIX}_SOSABI)
# Define lookup strategy
cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY)
@@ -1272,6 +1416,7 @@ unset (_${_PYTHON_PREFIX}_REGISTRY_VIEW)
if (CMAKE_SIZEOF_VOID_P)
math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
# In this case, search only for 64bit or 32bit
set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
@@ -1462,6 +1607,9 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}:")
+ endif()
if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
endif()
@@ -1478,6 +1626,9 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
_python_validate_library (CHECK_EXISTS)
endif()
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ _python_validate_sabi_library (CHECK_EXISTS)
+ 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)
@@ -1494,12 +1645,18 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE)
unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE CACHE)
+ unset (_${_PYTHON_PREFIX}_SABI_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 ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+ AND NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
OR ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR))
unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
@@ -1515,6 +1672,9 @@ function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module)
if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+ list (APPEND signature "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}:")
+ endif()
if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
endif()
@@ -1525,13 +1685,16 @@ function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module)
endif()
endfunction()
-
unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
unset (_${_PYTHON_PREFIX}_CACHED_VARS)
unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE CACHE INTERNAL "Interpreter reason failure")
unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE CACHE INTERNAL "Compiler reason failure")
+foreach (artifact IN LISTS _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ unset (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE)
+ set (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE CACHE INTERNAL "Development ${artifact} reason failure")
+endforeach()
unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE CACHE INTERNAL "Development reason failure")
unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
@@ -1868,6 +2031,13 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endif()
if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE)
+ list (LENGTH _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES _properties_length)
+ if (NOT _properties_length EQUAL "12")
+ # cache variable comes from some older Python module version: not usable
+ unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+ endif()
+ unset (_properties_length)
+
if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
@@ -1882,11 +2052,12 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
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}_SOSABI)
- 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)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDLIB)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_STDARCH)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITELIB)
+ list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 11 ${_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)
@@ -1985,10 +2156,11 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endif()
_python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+ _python_get_config_var (${_PYTHON_PREFIX}_SOSABI SOSABI)
# 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")
+ "${${_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}_SOSABI};${${_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)
@@ -2369,6 +2541,14 @@ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)
list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
endif()
endif()
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.SABIModule)
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_SABI_LIBRARIES)
+ endif()
+ if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_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)
@@ -2380,6 +2560,7 @@ 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.SABIModule" 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")
@@ -2400,11 +2581,18 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
_${_PYTHON_PREFIX}_LIBRARY_DEBUG
_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_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 (SABIModule)
_python_check_development_signature (Embed)
if (DEFINED ${_PYTHON_PREFIX}_LIBRARY
@@ -2413,6 +2601,12 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
endif()
+ if (DEFINED ${_PYTHON_PREFIX}_SABI_LIBRARY
+ AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_SABI_LIBRARY}")
+ set (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_SABI_LIBRARY}" CACHE INTERNAL "")
+ unset (_${_PYTHON_PREFIX}_SABI_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 "")
@@ -2429,7 +2623,8 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
endif()
endif()
- if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_SABI_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
@@ -2822,8 +3017,10 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+ else()
+ unset (_${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE CACHE)
endif()
set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
@@ -2871,18 +3068,280 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
endif()
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ ## compute artifact names
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} WIN32 POSIX LIBRARY)
+ _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} WIN32 DEBUG)
+
+ if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+ AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # SABI_LIBRARY_RELEASE search is based on LIBRARY_RELEASE
+ set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+
+ find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+ NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+ HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+ NO_DEFAULT_PATH)
+ else()
+ 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 SABI library
+ ## compute some paths
+ 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_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}_SABI_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}_SABI_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")
+ # 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}_SABI_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}_SABI_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}_SABI_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}_SABI_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_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}_SABI_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}_SABI_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}_SABI_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}_SABI_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()
+ endif()
+
+ # finalize library version information
+ _python_get_version (SABI_LIBRARY PREFIX _${_PYTHON_PREFIX}_)
+ # ABI library does not have the full version information
+ if (${_PYTHON_PREFIX}_Interpreter_FOUND OR _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ # update from interpreter or library
+ 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()
+
+ set (${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+
+ if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+ else()
+ unset (_${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE CACHE)
+ endif()
+
+ if (WIN32 AND _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ # search for debug library
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+ find_library (_${_PYTHON_PREFIX}_SABI_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}_SABI_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}_SABI_LIBRARY_RELEASE)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_SABI_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}_SABI_LIBRARY_DEBUG)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG}" DIRECTORY)
+ get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+ _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_SABI_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)
- set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED TRUE)
- foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Module Embed)
+ set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED FALSE)
+ set (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED FALSE)
+ foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Module SABIModule Embed)
string (TOUPPER "${_${_PYTHON_PREFIX}_COMPONENT}" _${_PYTHON_PREFIX}_ID)
if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
- AND NOT "LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
- set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED FALSE)
+ AND "LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
+ set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED TRUE)
+ endif()
+ if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND "SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
+ set (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED TRUE)
endif()
endforeach()
- if (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED
+ if ((_${_PYTHON_PREFIX}_LIBRARY_REQUIRED
AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+ AND (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED
+ AND NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE))
# Don't search for include dir if no library was founded
break()
endif()
@@ -2920,6 +3379,21 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
endif()
+ elseif ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+ AND _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+ # Use the library's install prefix as a hint
+ if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
+ list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+ elseif (_${_PYTHON_PREFIX}_SABI_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}_SABI_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}_SABI_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})
@@ -2983,8 +3457,10 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
- set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+ set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+ else()
+ unset (_${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE CACHE)
endif()
if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
@@ -3050,36 +3526,59 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
endif()
endif()
- if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR)
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ set (${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG}")
+ _python_select_library_configurations (${_PYTHON_PREFIX}_SABI)
+
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE}")
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG}")
+
+ if (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE)
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE}")
+ elseif (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG)
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG}")
+ else()
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY-NOTFOUND")
+ endif()
+
+ _python_set_library_dirs (${_PYTHON_PREFIX}_SABI_LIBRARY_DIRS
+ _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG)
+ if (UNIX)
+ if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+ set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})
+ endif()
+ else()
+ _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DIRS
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG)
+ endif()
+ endif()
+
+ if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_SABI_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 (SABIModule)
_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 (SABIModule)
_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.SABIModule_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 CACHE)
- endif()
-
if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
AND ${_PYTHON_PREFIX}_Development.Module_FOUND
AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
@@ -3087,13 +3586,14 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
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}")
+ OR ${_PYTHON_PREFIX}_Development.SABIModule_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)
@@ -3123,7 +3623,12 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
_python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
endif()
+ if (NOT DEFINED ${_PYTHON_PREFIX}_SOSABI)
+ _python_get_config_var (${_PYTHON_PREFIX}_SOSABI SOSABI)
+ endif()
+
_python_compute_development_signature (Module)
+ _python_compute_development_signature (SABIModule)
_python_compute_development_signature (Embed)
# Restore the original find library ordering
@@ -3135,6 +3640,9 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
set (${_PYTHON_PREFIX}_LIBRARY "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} Library")
endif()
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ set (${_PYTHON_PREFIX}_SABI_LIBRARY "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} ABI 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()
@@ -3144,6 +3652,10 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
_${_PYTHON_PREFIX}_LIBRARY_DEBUG
_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+ _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG
_${_PYTHON_PREFIX}_INCLUDE_DIR
_${_PYTHON_PREFIX}_CONFIG
_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE
@@ -3238,6 +3750,13 @@ endif()
unset (_${_PYTHON_PREFIX}_REASON_FAILURE)
foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)
+ if (_${_PYTHON_PREFIX}_COMPONENT STREQUAL "Development")
+ foreach (artifact IN LISTS _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+ if (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE)
+ _python_add_reason_failure ("Development" "${_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE}")
+ endif()
+ endforeach()
+ endif()
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 CACHE)
@@ -3271,12 +3790,19 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
AND ${_PYTHON_PREFIX}_Development.Module_FOUND)
+ OR ("Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+ AND ${_PYTHON_PREFIX}_Development.SABIModule_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)
+ if (${ARGC} GREATER 1)
+ set (_PREFIX "${ARGV1}_")
+ else()
+ set (_PREFIX "")
+ endif()
+ if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
+ OR ${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE)
set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
else()
set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
@@ -3289,37 +3815,37 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
set_property (TARGET ${__name}
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+ if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE)
# System manage shared libraries in two parts: import and runtime
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_${_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}")
+ IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}"
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_${_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}")
+ IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG}"
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}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}")
+ IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARIES}"
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE}")
endif()
else()
- if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+ if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_${_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}")
+ IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}")
set_target_properties (${__name}
PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
- IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+ IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG}")
else()
set_target_properties (${__name}
PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
- IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+ IMPORTED_LOCATION "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}")
endif()
endif()
@@ -3338,6 +3864,28 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
endif()
endmacro()
+ macro (__PYTHON_IMPORT_MODULE __name)
+ if (NOT TARGET ${__name})
+ add_library (${__name} INTERFACE IMPORTED)
+ endif()
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
+
+ # When available, enforce shared library generation with undefined symbols
+ if (APPLE)
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs")
+ endif()
+ if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ set_property (TARGET ${__name}
+ PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok")
+ endif()
+ endmacro()
+
if (${_PYTHON_PREFIX}_Development.Embed_FOUND)
__python_import_library (${_PYTHON_PREFIX}::Python)
endif()
@@ -3348,25 +3896,15 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
# 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}")
+ __python_import_module (${_PYTHON_PREFIX}::Module)
+ endif()
+ endif()
- # 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()
+ if (${_PYTHON_PREFIX}_Development.SABIModule_FOUND)
+ if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
+ __python_import_library (${_PYTHON_PREFIX}::SABIModule SABI)
+ else()
+ __python_import_module (${_PYTHON_PREFIX}::SABIModule)
endif()
endif()
@@ -3375,7 +3913,7 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
# 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" "" "")
+ cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY "STATIC;SHARED;MODULE;WITH_SOABI" "USE_SABI" "")
if (PYTHON_ADD_LIBRARY_STATIC)
set (type STATIC)
@@ -3385,9 +3923,51 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
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()
+ if (PYTHON_ADD_LIBRARY_USE_SABI)
+ if (NOT type STREQUAL MODULE)
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: 'USE_SABI' option is only valid for 'MODULE' type.")
+ return()
+ endif()
+ if (NOT PYTHON_ADD_LIBRARY_USE_SABI MATCHES "^(3)(\\.([0-9]+))?$")
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: ${PYTHON_ADD_LIBRARY_USE_SABI}: wrong version specified for 'USE_SABI'.")
+ return()
+ endif()
+ # compute value for Py_LIMITED_API macro
+ set (major_version "${CMAKE_MATCH_1}")
+ unset (minor_version)
+ if (CMAKE_MATCH_3)
+ set (minor_version "${CMAKE_MATCH_3}")
+ endif()
+ if (major_version EQUAL "3" AND NOT minor_version)
+ set (Py_LIMITED_API "3")
+ elseif ("${major_version}.${minor_version}" VERSION_LESS "3.2")
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: ${PYTHON_ADD_LIBRARY_USE_SABI}: invalid version. Version must be '3.2' or upper.")
+ return()
+ else()
+ set (Py_LIMITED_API "0x0${major_version}")
+ if (NOT minor_version)
+ string (APPEND Py_LIMITED_API "00")
+ else()
+ if (minor_version LESS 16)
+ string (APPEND Py_LIMITED_API "0")
+ endif()
+ math (EXPR minor_version "${minor_version}" OUTPUT_FORMAT HEXADECIMAL)
+ string (REGEX REPLACE "^0x(.+)$" "\\1" minor_version "${minor_version}")
+ string (APPEND Py_LIMITED_API "${minor_version}")
+ endif()
+ string (APPEND Py_LIMITED_API "0000")
+ endif()
+ endif()
+
+ if (type STREQUAL "MODULE")
+ if (PYTHON_ADD_LIBRARY_USE_SABI AND NOT TARGET ${prefix}::SABIModule)
+ message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::SABIModule' is not defined.\n Did you miss to request COMPONENT 'Development.SABIModule'?")
+ return()
+ endif()
+ if (NOT PYTHON_ADD_LIBRARY_USE_SABI 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()
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'?")
@@ -3399,23 +3979,37 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
get_property (type TARGET ${name} PROPERTY TYPE)
if (type STREQUAL "MODULE_LIBRARY")
- target_link_libraries (${name} PRIVATE ${prefix}::Module)
+ if (PYTHON_ADD_LIBRARY_USE_SABI)
+ target_compile_definitions (${name} PRIVATE Py_LIMITED_API=${Py_LIMITED_API})
+ target_link_libraries (${name} PRIVATE ${prefix}::SABIModule)
+ else()
+ target_link_libraries (${name} PRIVATE ${prefix}::Module)
+ endif()
# 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}")
+ if (PYTHON_ADD_LIBRARY_WITH_SOABI)
+ if (NOT PYTHON_ADD_LIBRARY_USE_SABI 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()
+ if (PYTHON_ADD_LIBRARY_USE_SABI AND ${prefix}_SOSABI)
+ get_property (suffix TARGET ${name} PROPERTY SUFFIX)
+ if (NOT suffix)
+ set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+ endif()
+ set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOSABI}${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.")
+ if (PYTHON_ADD_LIBRARY_WITH_SOABI OR PYTHON_ADD_LIBRARY_USE_SABI)
+ message (AUTHOR_WARNING "Find${prefix}: Options 'WITH_SOABI' and 'USE_SABI' are only supported for `MODULE` library type.")
endif()
target_link_libraries (${name} PRIVATE ${prefix}::Python)
endif()
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 268acfe..41d9b68 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -57,7 +57,7 @@ for you.
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``
+ with same platform architecture as the one defined by CMake
configuration. This constraint does not apply if only ``Interpreter``
component is specified.
@@ -388,7 +388,7 @@ setting the following variables:
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
+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:
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 4f198bb..ae086e8 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -31,6 +31,13 @@ The following components are supported:
* ``Development.Embed``: search for artifacts for Python 3 embedding
developments.
+ .. versionadded:: 3.26
+
+ * ``Development.SABIModule``: search for artifacts for Python 3 module
+ developments using the
+ `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_.
+ This component is available only for version ``3.2`` and upper.
+
* ``NumPy``: search for NumPy include directories.
.. versionadded:: 3.14
@@ -57,7 +64,7 @@ for you.
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``
+ with same platform architecture as the one defined by CMake
configuration. This constraint does not apply if only ``Interpreter``
component is specified.
@@ -81,6 +88,12 @@ This module defines the following :ref:`Imported Targets <Imported Targets>`:
Python 3 library for Python module. Target defined if component
``Development.Module`` is found.
+``Python3::SABIModule``
+ .. versionadded:: 3.26
+
+ Python 3 library for Python module using the Stable Application Binary
+ Interface. Target defined if component ``Development.SABIModule`` is found.
+
``Python3::Python``
Python 3 library for Python embedding. Target defined if component
``Development.Embed`` is found.
@@ -140,12 +153,21 @@ This module will set the following variables in your project
Extension suffix for modules.
- Information returned by
- ``distutils.sysconfig.get_config_var('SOABI')`` or computed from
- ``distutils.sysconfig.get_config_var('EXT_SUFFIX')`` or
+ Information computed from ``distutils.sysconfig.get_config_var('EXT_SUFFIX')``
+ or ``distutils.sysconfig.get_config_var('SOABI')`` 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.
+ not available, ``sysconfig.get_config_var('EXT_SUFFIX')`` or
+ ``sysconfig.get_config_var('SOABI')`` are used.
+
+``Python3_SOSABI``
+ .. versionadded:: 3.26
+
+ Extension suffix for modules using the Stable Application Binary Interface.
+
+ Information computed from ``importlib.machinery.EXTENSION_SUFFIXES`` if the
+ COMPONENT ``Interpreter`` was specified. Otherwise, the extension is ``abi3``
+ except for ``Windows``, ``MSYS`` and ``CYGWIN`` for which this is an empty
+ string.
``Python3_Compiler_FOUND``
System has the Python 3 compiler.
@@ -169,6 +191,12 @@ This module will set the following variables in your project
System has the Python 3 development artifacts for Python module.
+``Python3_Development.SABIModule_FOUND``
+ .. versionadded:: 3.26
+
+ System has the Python 3 development artifacts for Python module using the
+ Stable Application Binary Interface.
+
``Python3_Development.Embed_FOUND``
.. versionadded:: 3.18
@@ -190,6 +218,18 @@ This module will set the following variables in your project
The Python 3 library directories.
``Python3_RUNTIME_LIBRARY_DIRS``
The Python 3 runtime library directories.
+``Python3_SABI_LIBRARIES``
+ .. versionadded:: 3.26
+
+ The Python 3 libraries for the Stable Application Binary Interface.
+``Python3_SABI_LIBRARY_DIRS``
+ .. versionadded:: 3.26
+
+ The Python 3 ``SABI`` library directories.
+``Python3_RUNTIME_SABI_LIBRARY_DIRS``
+ .. versionadded:: 3.26
+
+ The Python 3 runtime ``SABI`` library directories.
``Python3_VERSION``
Python 3 version.
``Python3_VERSION_MAJOR``
@@ -424,6 +464,13 @@ setting the following variables:
variables ``Python3_LIBRARIES``, ``Python3_LIBRARY_DIRS`` and
``Python3_RUNTIME_LIBRARY_DIRS``.
+``Python3_SABI_LIBRARY``
+ .. versionadded:: 3.26
+
+ The path to the library for Stable Application Binary Interface. It will be
+ used to compute the variables ``Python3_SABI_LIBRARIES``,
+ ``Python3_SABI_LIBRARY_DIRS`` and ``Python3_RUNTIME_SABI_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``.
@@ -447,7 +494,7 @@ setting the following variables:
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
+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:
@@ -469,10 +516,11 @@ 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
+when library type is ``MODULE``, to target ``Python3::Module`` or
+``Python3::SABIModule`` (when ``USE_SABI`` option is specified) and takes care
of Python module naming rules::
- Python3_add_library (<name> [STATIC | SHARED | MODULE [WITH_SOABI]]
+ Python3_add_library (<name> [STATIC | SHARED | MODULE [USE_SABI <version>] [WITH_SOABI]]
<source1> [<source2> ...])
If the library type is not specified, ``MODULE`` is assumed.
@@ -480,6 +528,19 @@ 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.
+
+.. versionadded:: 3.26
+ For ``MODULE`` type, if the option ``USE_SABI`` is specified, the
+ preprocessor definition ``Py_LIMITED_API`` will be specified, as ``PRIVATE``,
+ for the target ``<name>`` with the value computed from ``<version>`` argument.
+ The expected format for ``<version>`` is ``major[.minor]``, where each
+ component is a numeric value. If ``minor`` component is specified, the
+ version should be, at least, ``3.2`` which is the version where the
+ `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_
+ was introduced. Specifying only major version ``3`` is equivalent to ``3.2``.
+
+ When option ``WITH_SOABI`` is also specified, the module suffix will include
+ the ``Python3_SOSABI`` value, if any.
#]=======================================================================]
diff --git a/Modules/FindQt4.cmake b/Modules/FindQt4.cmake
index ec0f453..3154ad3 100644
--- a/Modules/FindQt4.cmake
+++ b/Modules/FindQt4.cmake
@@ -623,7 +623,7 @@ if (QT_QMAKE_EXECUTABLE AND
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.")
+ message( FATAL_ERROR "Could NOT find QtCore.")
else()
return()
endif()
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
index 7326ef9..0fa6ae7 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -136,10 +136,8 @@ macro(_threads_check_flag_pthread)
try_compile(THREADS_HAVE_PTHREAD_ARG
SOURCE_FROM_FILE "${_threads_src}" "${CMAKE_CURRENT_LIST_DIR}/CheckForPthreads.c"
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)
@@ -233,16 +231,10 @@ if(THREADS_FOUND AND NOT TARGET Threads::Threads)
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>")
+ "$<$<AND:$<NOT:$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>>,$<NOT:$<COMPILE_LANGUAGE:Swift>>>:-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
index 97739fa..d71518f 100644
--- a/Modules/FindUnixCommands.cmake
+++ b/Modules/FindUnixCommands.cmake
@@ -5,6 +5,10 @@
FindUnixCommands
----------------
+.. deprecated:: 3.26
+
+ Use :option:`${CMAKE_COMMAND} -E <cmake -E>` subcommands instead.
+
Find Unix commands, including the ones from Cygwin
This module looks for the Unix commands ``bash``, ``cp``, ``gzip``,
diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake
index be5c775..d0deb87 100644
--- a/Modules/FindZLIB.cmake
+++ b/Modules/FindZLIB.cmake
@@ -20,33 +20,57 @@ 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``
+ .. versionadded:: 3.26
+ the version of Zlib found.
+
+ See also legacy variable ``ZLIB_VERSION_STRING``.
- ZLIB_INCLUDE_DIRS - where to find zlib.h, etc.
- ZLIB_LIBRARIES - List of libraries when using zlib.
- ZLIB_FOUND - True if zlib found.
+.. versionadded:: 3.4
+ Debug and Release variants are found separately.
-::
+Legacy Variables
+^^^^^^^^^^^^^^^^
- 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
+The following variables are provided for backward compatibility:
-.. versionadded:: 3.4
- Debug and Release variants are found separately.
+``ZLIB_VERSION_MAJOR``
+ The major version of zlib.
-Backward Compatibility
-^^^^^^^^^^^^^^^^^^^^^^
+ .. versionchanged:: 3.26
+ Superseded by ``ZLIB_VERSION``.
+``ZLIB_VERSION_MINOR``
+ The minor version of zlib.
-The following variable are provided for backward compatibility
+ .. versionchanged:: 3.26
+ Superseded by ``ZLIB_VERSION``.
+``ZLIB_VERSION_PATCH``
+ The patch version of zlib.
-::
+ .. versionchanged:: 3.26
+ Superseded by ``ZLIB_VERSION``.
+``ZLIB_VERSION_TWEAK``
+ The tweak version of zlib.
- ZLIB_MAJOR_VERSION - The major version of zlib
- ZLIB_MINOR_VERSION - The minor version of zlib
- ZLIB_PATCH_VERSION - The patch version of zlib
+ .. versionchanged:: 3.26
+ Superseded by ``ZLIB_VERSION``.
+``ZLIB_VERSION_STRING``
+ The version of zlib found (x.y.z)
+
+ .. versionchanged:: 3.26
+ Superseded by ``ZLIB_VERSION``.
+``ZLIB_MAJOR_VERSION``
+ The major version of zlib. Superseded by ``ZLIB_VERSION_MAJOR``.
+``ZLIB_MINOR_VERSION``
+ The minor version of zlib. Superseded by ``ZLIB_VERSION_MINOR``.
+``ZLIB_PATCH_VERSION``
+ The patch version of zlib. Superseded by ``ZLIB_VERSION_PATCH``.
Hints
^^^^^
@@ -60,6 +84,14 @@ module where to look.
#]=======================================================================]
+if(ZLIB_FIND_COMPONENTS AND NOT ZLIB_FIND_QUIETLY)
+ message(AUTHOR_WARNING
+ "ZLIB does not provide any COMPONENTS. Calling\n"
+ " find_package(ZLIB COMPONENTS ...)\n"
+ "will always fail."
+ )
+endif()
+
set(_ZLIB_SEARCHES)
# Search ZLIB_ROOT first if it is set.
@@ -160,11 +192,14 @@ if(ZLIB_INCLUDE_DIR AND EXISTS "${ZLIB_INCLUDE_DIR}/zlib.h")
set(ZLIB_MAJOR_VERSION "${ZLIB_VERSION_MAJOR}")
set(ZLIB_MINOR_VERSION "${ZLIB_VERSION_MINOR}")
set(ZLIB_PATCH_VERSION "${ZLIB_VERSION_PATCH}")
+
+ set(ZLIB_VERSION ${ZLIB_VERSION_STRING})
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB REQUIRED_VARS ZLIB_LIBRARY ZLIB_INCLUDE_DIR
- VERSION_VAR ZLIB_VERSION_STRING)
+ VERSION_VAR ZLIB_VERSION
+ HANDLE_COMPONENTS)
if(ZLIB_FOUND)
set(ZLIB_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR})
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
index 19eba95..3159ff7 100644
--- a/Modules/FindwxWidgets.cmake
+++ b/Modules/FindwxWidgets.cmake
@@ -615,7 +615,7 @@ if(wxWidgets_FIND_STYLE STREQUAL "win32")
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.")
+ DBG_MSG("wxWidgets_FOUND FALSE because ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h does not exist.")
set(wxWidgets_FOUND FALSE)
endif()
diff --git a/Modules/FindwxWindows.cmake b/Modules/FindwxWindows.cmake
index 2d46dbd..15dacbb 100644
--- a/Modules/FindwxWindows.cmake
+++ b/Modules/FindwxWindows.cmake
@@ -648,7 +648,7 @@ else()
# 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 (NOT APPLE) # -isystem seems to be unsupported 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`")
diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake
index af025af..ed8830e 100644
--- a/Modules/FortranCInterface.cmake
+++ b/Modules/FortranCInterface.cmake
@@ -381,13 +381,9 @@ function(FortranCInterface_VERIFY)
# 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)
diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake
index 6401aed..010661e 100644
--- a/Modules/FortranCInterface/Detect.cmake
+++ b/Modules/FortranCInterface/Detect.cmake
@@ -51,6 +51,7 @@ try_compile(FortranCInterface_COMPILED
TARGET FortranCInterface
SOURCE_DIR ${FortranCInterface_SOURCE_DIR}
BINARY_DIR ${FortranCInterface_BINARY_DIR}
+ LOG_DESCRIPTION "Fortran/C interface test project"
CMAKE_FLAGS
"-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
"-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
@@ -58,7 +59,7 @@ try_compile(FortranCInterface_COMPILED
"-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
${_FortranCInterface_OSX_ARCH}
${_FortranCInterface_EXE_LINKER_FLAGS}
- OUTPUT_VARIABLE FortranCInterface_OUTPUT)
+ )
set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
unset(FortranCInterface_COMPILED CACHE)
unset(_FortranCInterface_EXE_LINKER_FLAGS)
@@ -70,9 +71,6 @@ 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.
diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake
index b8dc482..57a7476 100644
--- a/Modules/GoogleTest.cmake
+++ b/Modules/GoogleTest.cmake
@@ -212,7 +212,7 @@ same as the Google Test name (i.e. ``suite.testcase``); see also
discovery. Note that the expression is a wildcard-based format that
matches against the original test names as used by gtest. For type or
value-parameterized tests, these names may be different to the potentially
- pretty-printed test names that ``ctest`` uses.
+ pretty-printed test names that :program:`ctest` uses.
``NO_PRETTY_TYPES``
By default, the type index of type-parameterized tests is replaced by the
@@ -405,6 +405,12 @@ function(gtest_add_tests)
--gtest_filter=${gtest_test_name}
${ARGS_EXTRA_ARGS}
)
+ # Makes sure a skipped GTest is reported as so by CTest
+ set_tests_properties(
+ ${ctest_test_name}
+ PROPERTIES
+ SKIP_REGULAR_EXPRESSION "\\[ SKIPPED \\]"
+ )
list(APPEND testList ${ctest_test_name})
endif()
endforeach()
diff --git a/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake
index d6fa5f0..ff8908b 100644
--- a/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake
+++ b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake
@@ -51,7 +51,7 @@ function(CMAKE_TRY_COMPILER_OR_LINKER_FLAG lang flag result)
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
+ message(CONFIGURE_LOG
"Function 'CMAKE_CHECK_COMPILER_FLAG' called with unsupported language: ${lang}\n")
set(${result} FALSE CACHE INTERNAL ${comment})
return()
@@ -69,7 +69,6 @@ function(CMAKE_TRY_COMPILER_OR_LINKER_FLAG lang flag result)
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
@@ -144,7 +143,7 @@ function(CMAKE_TRY_COMPILER_OR_LINKER_FLAG lang flag result)
endforeach()
endif()
if (DEFINED ${result})
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_LOG
"Determining if the ${flag} option "
"is supported for ${lang} language failed with the following output:\n"
"${COMPILER_FLAG_OUTPUT}\n")
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
index 7c10280..8ac1f6b 100644
--- a/Modules/Internal/CPack/CPackRPM.cmake
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -1200,7 +1200,7 @@ function(cpack_rpm_generate_package)
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")
+ 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 exist - ignoring")
endif()
else()
# reset SPEC var value if no file has been specified
@@ -1217,7 +1217,7 @@ function(cpack_rpm_generate_package)
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")
+ message(SEND_ERROR "CPackRPM:Warning: CPACK_RPM_CHANGELOG_FILE <${CPACK_RPM_CHANGELOG_FILE}> does not exist - 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)")
diff --git a/Modules/Internal/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake
index c011c24..61eada2 100644
--- a/Modules/Internal/CheckFlagCommonConfig.cmake
+++ b/Modules/Internal/CheckFlagCommonConfig.cmake
@@ -22,32 +22,30 @@ macro(CMAKE_CHECK_FLAG_COMMON_INIT _FUNC _LANG _SRC _PATTERNS)
FAIL_REGEX "-Werror=.* argument .* is not valid for C\\+\\+")
elseif("${_LANG}" STREQUAL "CUDA")
set(${_SRC} "__host__ int main() { return 0; }")
- set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU
- FAIL_REGEX "argument unused during compilation: .*") # Clang
+ set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+") # Host GNU
elseif("${_LANG}" STREQUAL "Fortran")
set(${_SRC} " program test\n stop\n end program")
set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Fortran")
elseif("${_LANG}" STREQUAL "HIP")
set(${_SRC} "__host__ int main() { return 0; }")
- set(${_PATTERNS} FAIL_REGEX "argument unused during compilation: .*") # Clang
elseif("${_LANG}" STREQUAL "OBJC")
set(${_SRC} [=[
#ifndef __OBJC__
# error "Not an Objective-C compiler"
#endif
int main(void) { return 0; }]=])
- set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C" # GNU
- FAIL_REGEX "argument unused during compilation: .*") # Clang
+ set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C") # GNU
elseif("${_LANG}" STREQUAL "OBJCXX")
set(${_SRC} [=[
#ifndef __OBJC__
# error "Not an Objective-C++ compiler"
#endif
int main(void) { return 0; }]=])
- set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+" # GNU
- FAIL_REGEX "argument unused during compilation: .*") # Clang
+ set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+") # GNU
elseif("${_LANG}" STREQUAL "ISPC")
set(${_SRC} "float func(uniform int32, float a) { return a / 2.25; }")
+ elseif("${_LANG}" STREQUAL "Swift")
+ set(${_SRC} "func blarpy() { }")
else()
message (SEND_ERROR "${_FUNC}: ${_LANG}: unknown language.")
return()
diff --git a/Modules/Internal/CheckSourceCompiles.cmake b/Modules/Internal/CheckSourceCompiles.cmake
index eadf3da..83d7020 100644
--- a/Modules/Internal/CheckSourceCompiles.cmake
+++ b/Modules/Internal/CheckSourceCompiles.cmake
@@ -9,7 +9,7 @@ cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var)
if(NOT DEFINED "${_var}")
-
+ set(_lang_filename "src")
if(_lang STREQUAL "C")
set(_lang_textual "C")
set(_lang_ext "c")
@@ -34,6 +34,13 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var)
elseif(_lang STREQUAL "OBJCXX")
set(_lang_textual "Objective-C++")
set(_lang_ext "mm")
+ elseif(_lang STREQUAL "Swift")
+ set(_lang_textual "Swift")
+ set(_lang_ext "swift")
+ if (NOT DEFINED CMAKE_TRY_COMPILE_TARGET_TYPE
+ OR CMAKE_TRY_COMPILE_TARGET_TYPE STREQUAL "EXECUTABLE")
+ set(_lang_filename "main")
+ endif()
else()
message (SEND_ERROR "check_source_compiles: ${_lang}: unknown language.")
return()
@@ -92,7 +99,7 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var)
endif()
string(APPEND _source "\n")
try_compile(${_var}
- SOURCE_FROM_VAR "src.${_SRC_EXT}" _source
+ SOURCE_FROM_VAR "${_lang_filename}.${_SRC_EXT}" _source
COMPILE_DEFINITIONS -D${_var} ${CMAKE_REQUIRED_DEFINITIONS}
${CHECK_${LANG}_SOURCE_COMPILES_ADD_LINK_OPTIONS}
${CHECK_${LANG}_SOURCE_COMPILES_ADD_LIBRARIES}
@@ -115,19 +122,11 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _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()
diff --git a/Modules/Internal/CheckSourceRuns.cmake b/Modules/Internal/CheckSourceRuns.cmake
index 09c85c5..805d98d 100644
--- a/Modules/Internal/CheckSourceRuns.cmake
+++ b/Modules/Internal/CheckSourceRuns.cmake
@@ -98,8 +98,7 @@ function(CMAKE_CHECK_SOURCE_RUNS _lang _source _var)
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)
@@ -111,13 +110,6 @@ function(CMAKE_CHECK_SOURCE_RUNS _lang _source _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)
@@ -128,14 +120,6 @@ function(CMAKE_CHECK_SOURCE_RUNS _lang _source _var)
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()
diff --git a/Modules/Internal/FeatureTesting.cmake b/Modules/Internal/FeatureTesting.cmake
index 5c144ec..1a8a27e 100644
--- a/Modules/Internal/FeatureTesting.cmake
+++ b/Modules/Internal/FeatureTesting.cmake
@@ -35,27 +35,25 @@ macro(_record_compiler_features lang compile_flags feature_list)
SOURCE_FROM_VAR "feature_tests.${lang_lc}" _content
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()
+ if(NOT CMAKE_${lang}_FEATURE_TEST)
+ set(_result 255)
+ elseif(_copy_error)
set(_result 255)
+ message(WARNING "${_copy_error}")
+ else()
+ set(_result 0)
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)
@@ -64,9 +62,6 @@ macro(_record_compiler_features lang compile_flags feature_list)
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()
diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake
index 3a279ca..aaaae9b 100644
--- a/Modules/Platform/Android-Clang.cmake
+++ b/Modules/Platform/Android-Clang.cmake
@@ -77,7 +77,9 @@ macro(__android_compiler_clang lang)
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}")
+ if("${lang}" STREQUAL "CXX")
+ list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
+ endif()
endif()
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set(_ANDROID_STL_NOSTDLIBXX 1)
diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake
index a4e9574..715f68b 100644
--- a/Modules/Platform/Android-Determine.cmake
+++ b/Modules/Platform/Android-Determine.cmake
@@ -70,7 +70,7 @@ if(CMAKE_GENERATOR MATCHES "Visual Studio")
endif()
endif()
if(VCXPROJ_INSPECT_RESULT)
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ message(CONFIGURE_LOG
"Determining the sysroot for the Android NDK failed.
The output was:
${VCXPROJ_INSPECT_RESULT}
@@ -78,7 +78,7 @@ ${VCXPROJ_INSPECT_OUTPUT}
")
else()
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ message(CONFIGURE_LOG
"Determining the sysroot for the Android NDK succeeded.
The output was:
${VCXPROJ_INSPECT_RESULT}
diff --git a/Modules/Platform/CYGWIN.cmake b/Modules/Platform/CYGWIN.cmake
index fc4ea2e..0b64496 100644
--- a/Modules/Platform/CYGWIN.cmake
+++ b/Modules/Platform/CYGWIN.cmake
@@ -1,48 +1,3 @@
-if("${CMAKE_MINIMUM_REQUIRED_VERSION}" VERSION_LESS "2.8.3.20101214" AND NOT MSYS)
- set(__USE_CMAKE_LEGACY_CYGWIN_WIN32 1)
-endif()
-if(NOT DEFINED WIN32 AND NOT MSYS)
- 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")
diff --git a/Modules/Platform/DOS-OpenWatcom-C.cmake b/Modules/Platform/DOS-OpenWatcom-C.cmake
index cf71c84..c6f65c0 100644
--- a/Modules/Platform/DOS-OpenWatcom-C.cmake
+++ b/Modules/Platform/DOS-OpenWatcom-C.cmake
@@ -1 +1,2 @@
include(Platform/DOS-OpenWatcom)
+__dos_open_watcom(C)
diff --git a/Modules/Platform/DOS-OpenWatcom-CXX.cmake b/Modules/Platform/DOS-OpenWatcom-CXX.cmake
index cf71c84..90d6407 100644
--- a/Modules/Platform/DOS-OpenWatcom-CXX.cmake
+++ b/Modules/Platform/DOS-OpenWatcom-CXX.cmake
@@ -1 +1,2 @@
include(Platform/DOS-OpenWatcom)
+__dos_open_watcom(CXX)
diff --git a/Modules/Platform/DOS-OpenWatcom.cmake b/Modules/Platform/DOS-OpenWatcom.cmake
index 54c452e..11a854c 100644
--- a/Modules/Platform/DOS-OpenWatcom.cmake
+++ b/Modules/Platform/DOS-OpenWatcom.cmake
@@ -20,9 +20,8 @@ set(CMAKE_SHARED_LIBRARY_C_FLAGS "-bd") # ... while this is a space separated st
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()
+macro(__dos_open_watcom lang)
+ if(NOT CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h)
+ endif()
+endmacro()
diff --git a/Modules/Platform/Linux-OpenWatcom.cmake b/Modules/Platform/Linux-OpenWatcom.cmake
index 678d373..731fd3c 100644
--- a/Modules/Platform/Linux-OpenWatcom.cmake
+++ b/Modules/Platform/Linux-OpenWatcom.cmake
@@ -23,16 +23,12 @@ unset(__LINUX_WATCOM_CMP0136)
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()
-
macro(__linux_open_watcom lang)
+ if(CMAKE_CROSSCOMPILING)
+ if(NOT CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/lh)
+ endif()
+ endif()
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreaded "")
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreaded -bm)
endmacro()
diff --git a/Modules/Platform/OS2-OpenWatcom.cmake b/Modules/Platform/OS2-OpenWatcom.cmake
index 720b953..9abcf28 100644
--- a/Modules/Platform/OS2-OpenWatcom.cmake
+++ b/Modules/Platform/OS2-OpenWatcom.cmake
@@ -27,22 +27,14 @@ unset(__OS2_WATCOM_CMP0136)
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()
-
macro(__os2_open_watcom lang)
+ if(NOT CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ if(DEFINED CMAKE_SYSTEM_PROCESSOR AND CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os21x)
+ else()
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/os2)
+ endif()
+ endif()
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreaded "")
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_SingleThreadedDLL -br)
set(CMAKE_${lang}_COMPILE_OPTIONS_WATCOM_RUNTIME_LIBRARY_MultiThreaded -bm)
diff --git a/Modules/Platform/Windows-OpenWatcom.cmake b/Modules/Platform/Windows-OpenWatcom.cmake
index 657a923..3e9795e 100644
--- a/Modules/Platform/Windows-OpenWatcom.cmake
+++ b/Modules/Platform/Windows-OpenWatcom.cmake
@@ -29,16 +29,12 @@ string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=nt -xs -dWIN32 ${_br_bm}")
unset(__WINDOWS_WATCOM_CMP0136)
unset(_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)
+ if(CMAKE_CROSSCOMPILING)
+ if(NOT CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
+ endif()
+ endif()
set(CMAKE_${lang}_CREATE_WIN32_EXE "system nt_win")
set(CMAKE_${lang}_CREATE_CONSOLE_EXE "system nt")
diff --git a/Modules/Platform/Windows3x-OpenWatcom-C.cmake b/Modules/Platform/Windows3x-OpenWatcom-C.cmake
new file mode 100644
index 0000000..68a8af6
--- /dev/null
+++ b/Modules/Platform/Windows3x-OpenWatcom-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows3x-OpenWatcom)
+__windows3x_open_watcom(C)
diff --git a/Modules/Platform/Windows3x-OpenWatcom-CXX.cmake b/Modules/Platform/Windows3x-OpenWatcom-CXX.cmake
new file mode 100644
index 0000000..182ef11
--- /dev/null
+++ b/Modules/Platform/Windows3x-OpenWatcom-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/Windows3x-OpenWatcom)
+__windows3x_open_watcom(CXX)
diff --git a/Modules/Platform/Windows3x-OpenWatcom.cmake b/Modules/Platform/Windows3x-OpenWatcom.cmake
new file mode 100644
index 0000000..6fcceea
--- /dev/null
+++ b/Modules/Platform/Windows3x-OpenWatcom.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.
+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 windows")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system windows")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system windows")
+else()
+ string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " system win386")
+ string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system win386")
+ string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system win386")
+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.
+
+set(CMAKE_RC_COMPILER "rc")
+
+set(CMAKE_WATCOM_RUNTIME_LIBRARY_DEFAULT "")
+
+string(APPEND CMAKE_C_FLAGS_INIT " -bt=windows")
+string(APPEND CMAKE_CXX_FLAGS_INIT " -bt=windows -xs")
+
+macro(__windows3x_open_watcom lang)
+ if(NOT CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
+ set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/win)
+ endif()
+endmacro()
diff --git a/Modules/Platform/Windows3x.cmake b/Modules/Platform/Windows3x.cmake
new file mode 100644
index 0000000..856f4b1
--- /dev/null
+++ b/Modules/Platform/Windows3x.cmake
@@ -0,0 +1,12 @@
+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/ProcessorCount.cmake b/Modules/ProcessorCount.cmake
index bda23ab..47e266d 100644
--- a/Modules/ProcessorCount.cmake
+++ b/Modules/ProcessorCount.cmake
@@ -22,9 +22,17 @@ 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.
+More generally accurate physical CPU count can be obtained via
+:command:`cmake_host_system_information`:
+
+.. code-block:: cmake
+
+ cmake_host_system_information(RESULT N
+ QUERY NUMBER_OF_PHYSICAL_CORES)
+
Example use, in a ctest -S dashboard script:
-::
+.. code-block:: cmake
include(ProcessorCount)
ProcessorCount(N)
@@ -33,8 +41,6 @@ Example use, in a ctest -S dashboard script:
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
diff --git a/Modules/SystemInformation.cmake b/Modules/SystemInformation.cmake
index 5ecc39a..97f3856 100644
--- a/Modules/SystemInformation.cmake
+++ b/Modules/SystemInformation.cmake
@@ -5,8 +5,8 @@
cmake_minimum_required(VERSION ${CMAKE_VERSION})
project(DumpInformation)
-# first get the standard information for th platform
-include_directories("This does not exists")
+# first get the standard information for the platform
+include_directories("This does not exist")
get_directory_property(incl INCLUDE_DIRECTORIES)
set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${DumpInformation_BINARY_DIR};${DumpInformation_SOURCE_DIR}")
@@ -83,8 +83,6 @@ macro(DUMP_FILE THE_FILE)
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})
diff --git a/Modules/TestBigEndian.cmake b/Modules/TestBigEndian.cmake
index 096c90c..12b6816 100644
--- a/Modules/TestBigEndian.cmake
+++ b/Modules/TestBigEndian.cmake
@@ -87,7 +87,6 @@ macro(__TEST_BIG_ENDIAN_LEGACY_IMPL VARIABLE)
try_compile(HAVE_${VARIABLE}
SOURCE_FROM_VAR "${_test_file}" TEST_ENDIANESS_FILE_CONTENT
- OUTPUT_VARIABLE OUTPUT
COPY_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestEndianess.bin" )
if(HAVE_${VARIABLE})
@@ -125,14 +124,8 @@ macro(__TEST_BIG_ENDIAN_LEGACY_IMPL VARIABLE)
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}\n${_test_file}:\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}\n${_test_file}:\n${TEST_ENDIANESS_FILE_CONTENT}\n\n")
set(${VARIABLE})
endif()
endif()
diff --git a/Modules/TestCXXAcceptsFlag.cmake b/Modules/TestCXXAcceptsFlag.cmake
index 2e511ae..023d6ba 100644
--- a/Modules/TestCXXAcceptsFlag.cmake
+++ b/Modules/TestCXXAcceptsFlag.cmake
@@ -27,17 +27,11 @@ macro(CHECK_CXX_ACCEPTS_FLAG FLAGS VARIABLE)
try_compile(${VARIABLE}
SOURCES ${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/TestForANSIForScope.cmake b/Modules/TestForANSIForScope.cmake
index 06db586..b1a12cf 100644
--- a/Modules/TestForANSIForScope.cmake
+++ b/Modules/TestForANSIForScope.cmake
@@ -19,21 +19,15 @@ if(NOT DEFINED CMAKE_ANSI_FOR_SCOPE)
message(CHECK_START "Check for ANSI scope")
try_compile(CMAKE_ANSI_FOR_SCOPE
SOURCES ${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.cxx b/Modules/TestForANSIStreamHeaders.cxx
index d314d58..0ae9723 100644
--- a/Modules/TestForANSIStreamHeaders.cxx
+++ b/Modules/TestForANSIStreamHeaders.cxx
@@ -1,6 +1,6 @@
#include <iostream>
-int main(int, char* [])
+int main(int, char*[])
{
return 0;
}
diff --git a/Modules/TestForAnsiForScope.cxx b/Modules/TestForAnsiForScope.cxx
index 4bc2c67..1632cae 100644
--- a/Modules/TestForAnsiForScope.cxx
+++ b/Modules/TestForAnsiForScope.cxx
@@ -1,4 +1,4 @@
-int main(int, char* [])
+int main(int, char*[])
{
int i;
for (int i = 0; i < 1; ++i)
diff --git a/Modules/TestForSSTREAM.cmake b/Modules/TestForSSTREAM.cmake
index 9a09ac7..e2cc5b0 100644
--- a/Modules/TestForSSTREAM.cmake
+++ b/Modules/TestForSSTREAM.cmake
@@ -18,21 +18,15 @@ if(NOT DEFINED CMAKE_HAS_ANSI_STRING_STREAM)
message(CHECK_START "Check for sstream")
try_compile(CMAKE_HAS_ANSI_STRING_STREAM
SOURCES ${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
index 83a75e4..59f13a3 100644
--- a/Modules/TestForSSTREAM.cxx
+++ b/Modules/TestForSSTREAM.cxx
@@ -1,5 +1,5 @@
#include <sstream>
-int main(int, char* [])
+int main(int, char*[])
{
std::ostringstream os;
os << "12345";
diff --git a/Modules/TestForSTDNamespace.cmake b/Modules/TestForSTDNamespace.cmake
index cd9c782..61e922d 100644
--- a/Modules/TestForSTDNamespace.cmake
+++ b/Modules/TestForSTDNamespace.cmake
@@ -18,21 +18,15 @@ if(NOT DEFINED CMAKE_STD_NAMESPACE)
message(CHECK_START "Check for STD namespace")
try_compile(CMAKE_STD_NAMESPACE
SOURCES ${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
index 62951ff..b537d44 100644
--- a/Modules/TestForSTDNamespace.cxx
+++ b/Modules/TestForSTDNamespace.cxx
@@ -1,5 +1,5 @@
#include <list>
-int main(int, char* [])
+int main(int, char*[])
{
std::list<int>();
return 0;
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index 1511bfd..54a8cf7 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -7,7 +7,7 @@ UseJava
This file provides support 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.
+information on how to load Java into your CMake project.
Synopsis
^^^^^^^^
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index fd6596b..ca16bc2 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -8,7 +8,14 @@ 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``:
+.. only:: html
+
+ .. contents::
+
+CMake Commands
+^^^^^^^^^^^^^^
+
+The following command is defined for use with ``SWIG``:
.. command:: swig_add_library
@@ -125,20 +132,8 @@ Defines the following command for use with ``SWIG``:
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.
+Properties on Source Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^
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
@@ -233,6 +228,9 @@ ensure generated files will receive the required settings.
other ways to define output file directory applies (see ``OUTFILE_DIR``
option of ``swig_add_library()`` command).
+Properties on Targets
+^^^^^^^^^^^^^^^^^^^^^
+
Target library properties can be set to apply same configuration to all SWIG
input files.
@@ -271,6 +269,9 @@ input files.
Add dependencies to all SWIG input files.
+Read-only Target Properties
+"""""""""""""""""""""""""""
+
The following target properties are output properties and can be used to get
information about support files generated by ``SWIG`` interface compilation.
@@ -303,6 +304,9 @@ information about support files generated by ``SWIG`` interface compilation.
When source property ``OUTPUT_DIR`` is defined, multiple directories can be
specified as part of ``SWIG_SUPPORT_FILES_DIRECTORY``.
+CMake Variables
+^^^^^^^^^^^^^^^
+
Some variables can be set to customize the behavior of ``swig_add_library``
as well as ``SWIG``:
@@ -361,6 +365,34 @@ as well as ``SWIG``:
.. versionadded:: 3.22
Added the support of :ref:`Visual Studio Generators`.
+Deprecated Commands
+^^^^^^^^^^^^^^^^^^^
+
+.. command:: swig_link_libraries
+
+ .. deprecated:: 3.13
+ Use :command:`target_link_libraries` with the standard target name,
+ or with ``${SWIG_MODULE_<name>_REAL_NAME}`` for legacy target naming.
+
+ Link libraries to swig module::
+
+ swig_link_libraries(<name> <item>...)
+
+ This command has same capabilities as :command:`target_link_libraries`
+ command.
+
+ .. note::
+ When policy :policy:`CMP0078` is set to ``NEW``,
+ :command:`swig_add_library` creates a standard target with the
+ specified ``<name>`` and :command:`target_link_libraries` must be used
+ instead of this command.
+
+ With the legacy behavior (when :policy:`CMP0078` is set to ``OLD`` and
+ the ``UseSWIG_TARGET_NAME_PREFERENCE`` variable is set to ``"LEGACY"``,
+ or in CMake versions prior to 3.12), it is preferable to use
+ ``target_link_libraries(${SWIG_MODULE_<name>_REAL_NAME} ...)``
+ instead of this command.
+
#]=======================================================================]
cmake_policy(PUSH)
@@ -378,6 +410,7 @@ set(SWIG_PYTHON_EXTRA_FILE_EXTENSIONS ".py")
set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java")
set(SWIG_CSHARP_EXTRA_FILE_EXTENSIONS ".cs" "PINVOKE.cs")
set(SWIG_PERL_EXTRA_FILE_EXTENSIONS ".pm")
+set(SWIG_PERL5_EXTRA_FILE_EXTENSIONS ".pm")
set(SWIG_MANAGE_SUPPORT_FILES_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/UseSWIG/ManageSupportFiles.cmake")
@@ -414,8 +447,8 @@ macro(SWIG_MODULE_INITIALIZE name language)
endif()
if(SWIG_MODULE_${name}_LANGUAGE STREQUAL "UNKNOWN")
message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
- elseif(SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" AND
- NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)
+ elseif((SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL" OR SWIG_MODULE_${name}_LANGUAGE STREQUAL "PERL5")
+ AND NOT "-shadow" IN_LIST SWIG_MODULE_${name}_EXTRA_FLAGS)
list(APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
endif()
endmacro()
@@ -971,7 +1004,7 @@ function(SWIG_ADD_LIBRARY name)
if (APPLE)
set_target_properties (${target_name} PROPERTIES SUFFIX ".bundle")
endif ()
- elseif (swig_lowercase_language STREQUAL "perl")
+ elseif (swig_lowercase_language STREQUAL "perl" OR swig_lowercase_language STREQUAL "perl5")
# assume empty prefix because we expect the module to be dynamically loaded
set_target_properties (${target_name} PROPERTIES PREFIX "")
if (APPLE)
diff --git a/Modules/UsewxWidgets.cmake b/Modules/UsewxWidgets.cmake
index eed0410..b428a61 100644
--- a/Modules/UsewxWidgets.cmake
+++ b/Modules/UsewxWidgets.cmake
@@ -38,18 +38,6 @@ 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)
@@ -57,45 +45,28 @@ if (wxWidgets_FOUND)
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/WriteBasicConfigVersionFile.cmake b/Modules/WriteBasicConfigVersionFile.cmake
index 45f9e58..1c5ecd5 100644
--- a/Modules/WriteBasicConfigVersionFile.cmake
+++ b/Modules/WriteBasicConfigVersionFile.cmake
@@ -46,6 +46,21 @@ function(WRITE_BASIC_CONFIG_VERSION_FILE _filename)
endif()
endif()
+ if(NOT CVF_ARCH_INDEPENDENT)
+ set(CVF_ARCH_INDEPENDENT_CHECK "
+# 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()")
+ endif()
+
configure_file("${versionTemplateFile}" "${_filename}" @ONLY)
endfunction()
diff --git a/Source/.gitattributes b/Source/.gitattributes
index d0aedc2..4b868dd 100644
--- a/Source/.gitattributes
+++ b/Source/.gitattributes
@@ -1,4 +1,4 @@
CMakeVersion.cmake export-subst
# Do not format third-party sources.
-/kwsys/** -format.clang-format-6.0
+/kwsys/** -format.clang-format
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c268a92..e99da49 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -160,6 +160,8 @@ add_library(
cmComputeLinkInformation.h
cmComputeTargetDepends.h
cmComputeTargetDepends.cxx
+ cmConfigureLog.h
+ cmConfigureLog.cxx
cmConsoleBuf.h
cmConsoleBuf.cxx
cmConstStack.h
@@ -196,9 +198,10 @@ add_library(
cmDependsCompiler.h
cmDocumentation.cxx
cmDocumentationFormatter.cxx
- cmDocumentationSection.cxx
cmDynamicLoader.cxx
cmDynamicLoader.h
+ cmDyndepCollation.cxx
+ cmDyndepCollation.h
cmELF.h
cmELF.cxx
cmExprParserHelper.cxx
@@ -234,6 +237,8 @@ add_library(
cmFileAPICache.h
cmFileAPICodemodel.cxx
cmFileAPICodemodel.h
+ cmFileAPIConfigureLog.cxx
+ cmFileAPIConfigureLog.h
cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h
cmFileAPIToolchains.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 7fb9246..de388f5 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
-set(CMake_VERSION_MINOR 25)
-set(CMake_VERSION_PATCH 2)
-#set(CMake_VERSION_RC 0)
+set(CMake_VERSION_MINOR 26)
+set(CMake_VERSION_PATCH 0)
+set(CMake_VERSION_RC 5)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index 9dd8fe3..bc14eb4 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -585,7 +585,7 @@ std::string cmCPackIFWGenerator::GetRootPackageName()
// Configure from root group
cmCPackIFWPackage package;
package.Generator = this;
- package.ConfigureFromGroup(optIFW_PACKAGE_GROUP);
+ package.ConfigureFromGroup(*optIFW_PACKAGE_GROUP);
name = package.Name;
} else if (cmValue optIFW_PACKAGE_NAME =
this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
index 2feca75..69440d9 100644
--- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -77,19 +77,20 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
// ApplicationIcon
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_ICON")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->InstallerApplicationIcon = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_ICON", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_ICON", *option);
}
}
// WindowIcon
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->InstallerWindowIcon = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WINDOW_ICON", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WINDOW_ICON",
+ *option);
}
}
@@ -104,37 +105,37 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
// Logo
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->Logo = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_LOGO", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_LOGO", *option);
}
}
// Watermark
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_WATERMARK")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->Watermark = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WATERMARK", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WATERMARK", *option);
}
}
// Banner
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_BANNER")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->Banner = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BANNER", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BANNER", *option);
}
}
// Background
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_BACKGROUND")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->Background = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BACKGROUND", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BACKGROUND", *option);
}
}
@@ -155,10 +156,11 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
// StyleSheet
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) {
- if (cmSystemTools::FileExists(option)) {
+ if (cmSystemTools::FileExists(*option)) {
this->StyleSheet = *option;
} else {
- this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option);
+ this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET",
+ *option);
}
}
@@ -276,9 +278,9 @@ void cmCPackIFWInstaller::ConfigureFromOptions()
// Control script
if (cmValue optIFW_CONTROL_SCRIPT =
this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) {
- if (!cmSystemTools::FileExists(optIFW_CONTROL_SCRIPT)) {
+ if (!cmSystemTools::FileExists(*optIFW_CONTROL_SCRIPT)) {
this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_CONTROL_SCRIPT",
- optIFW_CONTROL_SCRIPT);
+ *optIFW_CONTROL_SCRIPT);
} else {
this->ControlScript = *optIFW_CONTROL_SCRIPT;
}
@@ -653,9 +655,9 @@ void cmCPackIFWInstaller::GeneratePackageFiles()
package.Installer = this;
// Check package group
if (cmValue option = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
- package.ConfigureFromGroup(option);
+ package.ConfigureFromGroup(*option);
std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" +
- cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION";
+ cmsys::SystemTools::UpperCase(*option) + "_FORCED_INSTALLATION";
if (!this->GetOption(forcedOption)) {
package.ForcedInstallation = "true";
}
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
index c2109c9..1668fb5 100644
--- a/Source/CPack/IFW/cmCPackIFWPackage.cxx
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -382,7 +382,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
if (this->IsSetToEmpty(option)) {
this->DisplayName.clear();
} else if (cmValue value = this->GetOption(option)) {
- cmCPackIFWPackage::ExpandListArgument(value, this->DisplayName);
+ cmCPackIFWPackage::ExpandListArgument(*value, this->DisplayName);
}
// Description
@@ -390,7 +390,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
if (this->IsSetToEmpty(option)) {
this->Description.clear();
} else if (cmValue value = this->GetOption(option)) {
- cmCPackIFWPackage::ExpandListArgument(value, this->Description);
+ cmCPackIFWPackage::ExpandListArgument(*value, this->Description);
}
// Release date
@@ -484,7 +484,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix)
if (this->IsSetToEmpty(option)) {
this->Default.clear();
} else if (cmValue value = this->GetOption(option)) {
- std::string lowerValue = cmsys::SystemTools::LowerCase(value);
+ std::string lowerValue = cmsys::SystemTools::LowerCase(*value);
if (lowerValue == "true") {
this->Default = "true";
} else if (lowerValue == "false") {
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 5dae966..aeb3db3 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -422,9 +422,9 @@ void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
cmValue value = GetOption(name);
if (value) {
if (type == DefinitionType::PATH) {
- AddDefinition(source, name, CMakeToWixPath(value));
+ AddDefinition(source, name, CMakeToWixPath(*value));
} else {
- AddDefinition(source, name, value);
+ AddDefinition(source, name, *value);
}
}
}
@@ -504,7 +504,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
}
featureDefinitions.AddAttribute("Title", featureTitle);
if (cmValue desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) {
- featureDefinitions.AddAttribute("Description", desc);
+ featureDefinitions.AddAttribute("Description", *desc);
}
featureDefinitions.AddAttribute("Level", "1");
this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
@@ -512,7 +512,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
cmValue package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
if (package) {
featureDefinitions.CreateCMakePackageRegistryEntry(
- package, GetOption("CPACK_WIX_UPGRADE_GUID"));
+ *package, GetOption("CPACK_WIX_UPGRADE_GUID"));
}
if (!CreateFeatureHierarchy(featureDefinitions)) {
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index 894c24b..c9c069c 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -80,10 +80,10 @@ std::string cmCPackArchiveGenerator::GetArchiveComponentFileName(
*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);
+ *this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName);
} else {
packageFileName += this->GetComponentPackageFileName(
- this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName);
+ *this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName);
}
packageFileName += this->GetOutputExtension();
@@ -357,9 +357,9 @@ int cmCPackArchiveGenerator::GetThreadCount() const
// CPACK_ARCHIVE_THREADS overrides CPACK_THREADS
if (this->IsSet("CPACK_ARCHIVE_THREADS")) {
- threads = std::stoi(this->GetOption("CPACK_ARCHIVE_THREADS"));
+ threads = std::stoi(*this->GetOption("CPACK_ARCHIVE_THREADS"));
} else if (this->IsSet("CPACK_THREADS")) {
- threads = std::stoi(this->GetOption("CPACK_THREADS"));
+ threads = std::stoi(*this->GetOption("CPACK_THREADS"));
}
return threads;
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index a3b9434..6ba28d1 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -124,8 +124,8 @@ DebGenerator::DebGenerator(
<< debianCompressionType << std::endl);
}
- if (numThreads != nullptr) {
- if (!cmStrToLong(numThreads, &this->NumThreads)) {
+ if (numThreads) {
+ if (!cmStrToLong(*numThreads, &this->NumThreads)) {
this->NumThreads = 1;
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Unrecognized number of threads: " << numThreads
@@ -703,7 +703,7 @@ bool cmCPackDebGenerator::createDebPackages()
&cmCPackDebGenerator::createDeb);
cmValue dbgsymdir_path = this->GetOption("GEN_DBGSYMDIR");
if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && dbgsymdir_path) {
- retval = make_package(dbgsymdir_path, "GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME",
+ retval = make_package(*dbgsymdir_path, "GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME",
&cmCPackDebGenerator::createDbgsymDDeb) &&
retval;
}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 0579066..68e7ba3 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -451,7 +451,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
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);
+ temp_mount.substr(cmStrLen("/Volumes/"));
// Remove dummy padding file so we have enough space on RW image ...
std::ostringstream dummy_padding;
diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx
index edd8490..4c92592 100644
--- a/Source/CPack/cmCPackExternalGenerator.cxx
+++ b/Source/CPack/cmCPackExternalGenerator.cxx
@@ -63,7 +63,7 @@ int cmCPackExternalGenerator::PackageFiles()
cmValue packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT");
if (cmNonempty(packageScript)) {
- if (!cmSystemTools::FileIsFullPath(packageScript)) {
+ if (!cmSystemTools::FileIsFullPath(*packageScript)) {
cmCPackLogger(
cmCPackLog::LOG_ERROR,
"CPACK_EXTERNAL_PACKAGE_SCRIPT does not contain a full file path"
@@ -71,7 +71,7 @@ int cmCPackExternalGenerator::PackageFiles()
return 0;
}
- bool res = this->MakefileMap->ReadListFile(packageScript);
+ bool res = this->MakefileMap->ReadListFile(*packageScript);
if (cmSystemTools::GetErrorOccurredFlag() || !res) {
return 0;
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 90d15f8..2ac5b3d 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -91,7 +91,7 @@ int cmCPackGenerator::PrepareNames()
"CPACK_PACKAGE_FILE_NAME not specified" << std::endl);
return 0;
}
- std::string outName = pfname;
+ std::string outName = *pfname;
tempDirectory += "/" + outName;
if (!this->GetOutputExtension()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
@@ -106,7 +106,7 @@ int cmCPackGenerator::PrepareNames()
return 0;
}
- std::string destFile = pdir;
+ std::string destFile = *pdir;
this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile);
destFile += "/" + outName;
std::string outFile = topDirectory + "/" + outName;
@@ -126,17 +126,17 @@ int cmCPackGenerator::PrepareNames()
cmValue 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)) {
+ "Look for: " << *descFileName << std::endl);
+ if (!cmSystemTools::FileExists(*descFileName)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Cannot find description file name: ["
- << descFileName << "]" << std::endl);
+ << *descFileName << "]" << std::endl);
return 0;
}
cmsys::ifstream ifs(descFileName->c_str());
if (!ifs) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Cannot open description file name: " << descFileName
+ "Cannot open description file name: " << *descFileName
<< std::endl);
return 0;
}
@@ -144,14 +144,14 @@ int cmCPackGenerator::PrepareNames()
std::string line;
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
- "Read description file: " << descFileName << std::endl);
+ "Read description file: " << *descFileName << std::endl);
while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
ostr << cmXMLSafe(line) << std::endl;
}
this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str());
cmValue defFileName =
this->GetOption("CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE");
- if (defFileName && (defFileName == descFileName)) {
+ if (defFileName && (*defFileName == *descFileName)) {
this->SetOption("CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE", "ON");
}
}
@@ -636,7 +636,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
std::unique_ptr<cmGlobalGenerator> globalGenerator =
this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator(
- cmakeGenerator);
+ *cmakeGenerator);
if (!globalGenerator) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Specified package generator not found. "
@@ -1050,14 +1050,14 @@ int cmCPackGenerator::DoPackage()
if (cmIsOn(this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY"))) {
cmValue toplevelDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
- if (cmSystemTools::FileExists(toplevelDirectory)) {
+ if (toplevelDirectory && cmSystemTools::FileExists(*toplevelDirectory)) {
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
- "Remove toplevel directory: " << toplevelDirectory
+ "Remove toplevel directory: " << *toplevelDirectory
<< std::endl);
- if (!cmSystemTools::RepeatedRemoveDirectory(toplevelDirectory)) {
+ if (!cmSystemTools::RepeatedRemoveDirectory(*toplevelDirectory)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem removing toplevel directory: "
- << toplevelDirectory << std::endl);
+ << *toplevelDirectory << std::endl);
return 0;
}
}
@@ -1091,10 +1091,10 @@ int cmCPackGenerator::DoPackage()
"Package files to: "
<< (tempPackageFileName ? *tempPackageFileName : "(NULL)")
<< std::endl);
- if (cmSystemTools::FileExists(tempPackageFileName)) {
+ if (tempPackageFileName && cmSystemTools::FileExists(*tempPackageFileName)) {
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Remove old package file" << std::endl);
- cmSystemTools::RemoveFile(tempPackageFileName);
+ cmSystemTools::RemoveFile(*tempPackageFileName);
}
if (cmIsOn(this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
tempDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
@@ -1211,7 +1211,7 @@ int cmCPackGenerator::Initialize(const std::string& name, cmMakefile* mf)
// Load the project specific config file
cmValue config = this->GetOption("CPACK_PROJECT_CONFIG_FILE");
if (config) {
- mf->ReadListFile(config);
+ mf->ReadListFile(*config);
}
int result = this->InitializeInternal();
if (cmSystemTools::GetErrorOccurredFlag()) {
@@ -1581,7 +1581,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent(
cmValue groupName = this->GetOption(macroPrefix + "_GROUP");
if (cmNonempty(groupName)) {
- component->Group = this->GetComponentGroup(projectName, groupName);
+ component->Group = this->GetComponentGroup(projectName, *groupName);
component->Group->Components.push_back(component);
} else {
component->Group = nullptr;
@@ -1644,7 +1644,7 @@ cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup(
cmValue parentGroupName = this->GetOption(macroPrefix + "_PARENT_GROUP");
if (cmNonempty(parentGroupName)) {
group->ParentGroup =
- this->GetComponentGroup(projectName, parentGroupName);
+ this->GetComponentGroup(projectName, *parentGroupName);
group->ParentGroup->Subgroups.push_back(group);
} else {
group->ParentGroup = nullptr;
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 65156ab..8078d9f 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -344,8 +344,14 @@ private:
#define cmCPackTypeMacro(klass, superclass) \
using Superclass = superclass; \
- const char* GetNameOfClass() override { return #klass; } \
- static cmCPackGenerator* CreateGenerator() { return new klass; } \
+ const char* GetNameOfClass() override \
+ { \
+ return #klass; \
+ } \
+ static cmCPackGenerator* CreateGenerator() \
+ { \
+ return new klass; \
+ } \
class cmCPackTypeMacro_UseTrailingSemicolon
#define cmCPackLogger(logType, msg) \
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 6ca5783..d7119c5 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -473,7 +473,7 @@ int cmCPackNSISGenerator::InitializeInternal()
this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLE", "makensis");
nsisPath = cmSystemTools::FindProgram(
- this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false);
+ *this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false);
if (nsisPath.empty()) {
cmCPackLogger(
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
index 7b9f6cf..76ef091 100644
--- a/Source/CPack/cmCPackPKGGenerator.cxx
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -58,16 +58,17 @@ void cmCPackPKGGenerator::CreateBackground(const char* themeName,
? cmStrCat("CPACK_", genName, "_BACKGROUND")
: cmStrCat("CPACK_", genName, "_BACKGROUND_", paramSuffix);
cmValue bgFileName = this->GetOption(opt);
- if (bgFileName == nullptr) {
+ if (!bgFileName) {
return;
}
- std::string bgFilePath = cmStrCat(metapackageFile, "/Contents/", bgFileName);
+ 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);
+ << *bgFileName << std::endl);
return;
}
@@ -77,16 +78,16 @@ void cmCPackPKGGenerator::CreateBackground(const char* themeName,
xout.StartElement(cmStrCat("background-", themeName));
}
- xout.Attribute("file", bgFileName);
+ xout.Attribute("file", *bgFileName);
cmValue param = this->GetOption(cmStrCat(opt, "_ALIGNMENT"));
if (param != nullptr) {
- xout.Attribute("alignment", param);
+ xout.Attribute("alignment", *param);
}
param = this->GetOption(cmStrCat(opt, "_SCALING"));
if (param != nullptr) {
- xout.Attribute("scaling", param);
+ xout.Attribute("scaling", *param);
}
// Apple docs say that you must provide either mime-type or uti
@@ -94,12 +95,12 @@ void cmCPackPKGGenerator::CreateBackground(const char* themeName,
// 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);
+ xout.Attribute("mime-type", *param);
}
param = this->GetOption(cmStrCat(opt, "_UTI"));
if (param != nullptr) {
- xout.Attribute("uti", param);
+ xout.Attribute("uti", *param);
}
xout.EndElement();
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index f06946b..2257118 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -5,10 +5,12 @@
#include <cstddef>
#include <functional>
#include <iostream>
+#include <iterator>
#include <map>
#include <memory>
#include <sstream>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -25,7 +27,6 @@
#include "cmConsoleBuf.h"
#include "cmDocumentation.h"
#include "cmDocumentationEntry.h"
-#include "cmDocumentationFormatter.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
@@ -36,19 +37,14 @@
#include "cmake.h"
namespace {
-const char* cmDocumentationName[][2] = {
- { nullptr, " cpack - Packaging driver provided by CMake." },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationName = {
+ {},
+ " cpack - Packaging driver provided by CMake."
};
-const char* cmDocumentationUsage[][2] = {
- // clang-format off
- { nullptr, " cpack [options]" },
- { nullptr, nullptr }
- // clang-format on
-};
+const cmDocumentationEntry cmDocumentationUsage = { {}, " cpack [options]" };
-const char* cmDocumentationOptions[][2] = {
+const cmDocumentationEntry cmDocumentationOptions[14] = {
{ "-G <generators>", "Override/define CPACK_GENERATOR" },
{ "-C <Configuration>", "Specify the project configuration" },
{ "-D <var>=<value>", "Set a CPack variable." },
@@ -62,14 +58,30 @@ const char* cmDocumentationOptions[][2] = {
{ "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" },
{ "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" },
{ "--preset", "Read arguments from a package preset" },
- { "--list-presets", "List available package presets" },
- { nullptr, nullptr }
+ { "--list-presets", "List available package presets" }
};
void cpackProgressCallback(const std::string& message, float /*unused*/)
{
- std::cout << "-- " << message << std::endl;
+ std::cout << "-- " << message << '\n';
}
+
+std::vector<cmDocumentationEntry> makeGeneratorDocs(
+ const cmCPackGeneratorFactory& gf)
+{
+ const auto& generators = gf.GetGeneratorsList();
+
+ std::vector<cmDocumentationEntry> docs;
+ docs.reserve(generators.size());
+
+ std::transform(
+ generators.cbegin(), generators.cend(), std::back_inserter(docs),
+ [](const std::decay<decltype(generators)>::type::value_type& gen) {
+ return cmDocumentationEntry{ gen.first, gen.second };
+ });
+ return docs;
+}
+
} // namespace
// this is CPack.
@@ -101,8 +113,7 @@ int main(int argc, char const* const* argv)
if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Current working directory cannot be established."
- << std::endl);
+ "Current working directory cannot be established.\n");
return 1;
}
@@ -129,14 +140,14 @@ int main(int argc, char const* const* argv)
auto const verboseLambda = [&log](const std::string&, cmake*,
cmMakefile*) -> bool {
log.SetVerbose(true);
- cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose\n");
return true;
};
auto const debugLambda = [&log](const std::string&, cmake*,
cmMakefile*) -> bool {
log.SetDebug(true);
- cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug\n");
return true;
};
@@ -194,26 +205,25 @@ int main(int argc, char const* const* argv)
CommandArgument::setToValue(preset) },
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
CommandArgument::setToTrue(listPresets) },
- CommandArgument{
- "-D", CommandArgument::Values::One,
- [&log, &definitions](const std::string& arg, cmake*,
- cmMakefile*) -> bool {
- std::string value = arg;
- size_t pos = value.find_first_of('=');
- if (pos == std::string::npos) {
- cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Please specify CPack definitions as: KEY=VALUE"
- << std::endl);
- return false;
- }
- std::string key = value.substr(0, pos);
- value.erase(0, pos + 1);
- definitions[key] = value;
- cmCPack_Log(&log, cmCPackLog::LOG_DEBUG,
- "Set CPack variable: " << key << " to \"" << value << "\""
- << std::endl);
- return true;
- } },
+ CommandArgument{ "-D", CommandArgument::Values::One,
+ [&log, &definitions](const std::string& arg, cmake*,
+ cmMakefile*) -> bool {
+ std::string value = arg;
+ size_t pos = value.find_first_of('=');
+ if (pos == std::string::npos) {
+ cmCPack_Log(
+ &log, cmCPackLog::LOG_ERROR,
+ "Please specify CPack definitions as: KEY=VALUE\n");
+ return false;
+ }
+ std::string key = value.substr(0, pos);
+ value.erase(0, pos + 1);
+ definitions[key] = value;
+ cmCPack_Log(&log, cmCPackLog::LOG_DEBUG,
+ "Set CPack variable: " << key << " to \""
+ << value << "\"\n");
+ return true;
+ } },
};
cmake cminst(cmake::RoleScript, cmState::CPack);
@@ -223,9 +233,6 @@ int main(int argc, char const* const* argv)
cminst.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator cmgg(&cminst);
cmMakefile globalMF(&cmgg, cminst.GetCurrentSnapshot());
-#if defined(__CYGWIN__)
- globalMF.AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
-#endif
bool parsed = true;
for (std::size_t i = 0; i < inputArgs.size(); i++) {
@@ -262,8 +269,7 @@ int main(int argc, char const* const* argv)
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Could not read presets from "
<< workingDirectory << ": "
- << cmCMakePresetsGraph::ResultToString(result)
- << std::endl);
+ << cmCMakePresetsGraph::ResultToString(result) << '\n');
return 1;
}
@@ -276,7 +282,7 @@ int main(int argc, char const* const* argv)
if (presetPair == presetsGraph.PackagePresets.end()) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"No such package preset in " << workingDirectory << ": \""
- << preset << '"' << std::endl);
+ << preset << "\"\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
@@ -284,8 +290,7 @@ int main(int argc, char const* const* argv)
if (presetPair->second.Unexpanded.Hidden) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot use hidden package preset in "
- << workingDirectory << ": \"" << preset << '"'
- << std::endl);
+ << workingDirectory << ": \"" << preset << "\"\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
@@ -294,7 +299,7 @@ int main(int argc, char const* const* argv)
if (!expandedPreset) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Could not evaluate package preset \""
- << preset << "\": Invalid macro expansion" << std::endl);
+ << preset << "\": Invalid macro expansion\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
@@ -302,8 +307,7 @@ int main(int argc, char const* const* argv)
if (!expandedPreset->ConditionResult) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot use disabled package preset in "
- << workingDirectory << ": \"" << preset << '"'
- << std::endl);
+ << workingDirectory << ": \"" << preset << "\"\n");
presetsGraph.PrintPackagePresetList(presetGeneratorsPresent);
return 1;
}
@@ -320,7 +324,7 @@ int main(int argc, char const* const* argv)
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"No such configure preset in "
<< workingDirectory << ": \""
- << expandedPreset->ConfigurePreset << '"' << std::endl);
+ << expandedPreset->ConfigurePreset << "\"\n");
presetsGraph.PrintConfigurePresetList();
return 1;
}
@@ -329,7 +333,7 @@ int main(int argc, char const* const* argv)
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot use hidden configure preset in "
<< workingDirectory << ": \""
- << expandedPreset->ConfigurePreset << '"' << std::endl);
+ << expandedPreset->ConfigurePreset << "\"\n");
presetsGraph.PrintConfigurePresetList();
return 1;
}
@@ -339,7 +343,7 @@ int main(int argc, char const* const* argv)
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Could not evaluate configure preset \""
<< expandedPreset->ConfigurePreset
- << "\": Invalid macro expansion" << std::endl);
+ << "\": Invalid macro expansion\n");
return 1;
}
@@ -395,7 +399,7 @@ int main(int argc, char const* const* argv)
}
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
- "Read CPack config file: " << cpackConfigFile << std::endl);
+ "Read CPack config file: " << cpackConfigFile << '\n');
bool cpackConfigFileSpecified = true;
if (cpackConfigFile.empty()) {
@@ -423,7 +427,7 @@ int main(int argc, char const* const* argv)
globalMF.GetModulesFile("CMakeDetermineSystem.cmake");
if (!globalMF.ReadListFile(systemFile)) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Error reading CMakeDetermineSystem.cmake" << std::endl);
+ "Error reading CMakeDetermineSystem.cmake\n");
return 1;
}
@@ -431,8 +435,7 @@ int main(int argc, char const* const* argv)
globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake");
if (!globalMF.ReadListFile(systemFile)) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Error reading CMakeSystemSpecificInformation.cmake"
- << std::endl);
+ "Error reading CMakeSystemSpecificInformation.cmake\n");
return 1;
}
@@ -444,17 +447,17 @@ int main(int argc, char const* const* argv)
cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
"Read CPack configuration file: " << cpackConfigFile
- << std::endl);
+ << '\n');
if (!globalMF.ReadListFile(cpackConfigFile)) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Problem reading CPack config file: \""
- << cpackConfigFile << "\"" << std::endl);
+ "Problem reading CPack config file: \"" << cpackConfigFile
+ << "\"\n");
return 1;
}
} else if (cpackConfigFileSpecified) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Cannot find CPack config file: \"" << cpackConfigFile
- << "\"" << std::endl);
+ << "\"\n");
return 1;
}
@@ -503,17 +506,17 @@ int main(int argc, char const* const* argv)
cmValue genList = globalMF.GetDefinition("CPACK_GENERATOR");
if (!genList) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "CPack generator not specified" << std::endl);
+ "CPack generator not specified\n");
} else {
std::vector<std::string> generatorsVector = cmExpandedList(*genList);
for (std::string const& gen : generatorsVector) {
cmMakefile::ScopePushPop raii(&globalMF);
cmMakefile* mf = &globalMF;
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
- "Specified generator: " << gen << std::endl);
+ "Specified generator: " << gen << '\n');
if (!mf->GetDefinition("CPACK_PACKAGE_NAME")) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "CPack project name not specified" << std::endl);
+ "CPack project name not specified" << '\n');
parsed = false;
}
if (parsed &&
@@ -522,13 +525,11 @@ int main(int argc, char const* const* argv)
mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "CPack project version not specified"
- << std::endl
- << "Specify CPACK_PACKAGE_VERSION, or "
- "CPACK_PACKAGE_VERSION_MAJOR, "
- "CPACK_PACKAGE_VERSION_MINOR, and "
- "CPACK_PACKAGE_VERSION_PATCH."
- << std::endl);
+ "CPack project version not specified\n"
+ "Specify CPACK_PACKAGE_VERSION, or "
+ "CPACK_PACKAGE_VERSION_MAJOR, "
+ "CPACK_PACKAGE_VERSION_MINOR, and "
+ "CPACK_PACKAGE_VERSION_PATCH.\n");
parsed = false;
}
if (parsed) {
@@ -539,19 +540,12 @@ int main(int argc, char const* const* argv)
cpackGenerator->SetTraceExpand(cminst.GetTraceExpand());
} else {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Could not create CPack generator: " << gen
- << std::endl);
+ "Could not create CPack generator: " << gen << '\n');
// Print out all the valid generators
cmDocumentation generatorDocs;
- std::vector<cmDocumentationEntry> v;
- for (auto const& g : generators.GetGeneratorsList()) {
- cmDocumentationEntry e;
- e.Name = g.first;
- e.Brief = g.second;
- v.push_back(std::move(e));
- }
- generatorDocs.SetSection("Generators", v);
- std::cerr << "\n";
+ generatorDocs.SetSection("Generators",
+ makeGeneratorDocs(generators));
+ std::cerr << '\n';
generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators,
std::cerr);
parsed = false;
@@ -559,8 +553,7 @@ int main(int argc, char const* const* argv)
if (parsed && !cpackGenerator->Initialize(gen, mf)) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
- "Cannot initialize the generator " << gen
- << std::endl);
+ "Cannot initialize the generator " << gen << '\n');
parsed = false;
}
@@ -573,17 +566,16 @@ int main(int argc, char const* const* argv)
"Please specify build tree of the project that uses CMake "
"using CPACK_INSTALL_CMAKE_PROJECTS, specify "
"CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or "
- "CPACK_INSTALLED_DIRECTORIES."
- << std::endl);
+ "CPACK_INSTALLED_DIRECTORIES.\n");
parsed = false;
}
if (parsed) {
cmValue projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
"Use generator: " << cpackGenerator->GetNameOfClass()
- << std::endl);
+ << '\n');
cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
- "For project: " << *projName << std::endl);
+ "For project: " << *projName << '\n');
cmValue projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION");
if (!projVersion) {
@@ -594,7 +586,7 @@ int main(int argc, char const* const* argv)
cmValue projVersionPatch =
mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
std::ostringstream ostr;
- ostr << *projVersionMajor << "." << *projVersionMinor << "."
+ ostr << *projVersionMajor << "." << *projVersionMinor << '.'
<< *projVersionPatch;
mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str());
}
@@ -603,7 +595,7 @@ int main(int argc, char const* const* argv)
if (!res) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Error when generating package: " << *projName
- << std::endl);
+ << '\n');
return 1;
}
}
@@ -618,27 +610,13 @@ int main(int argc, char const* const* argv)
*/
if (help) {
// Construct and print requested documentation.
-
doc.SetName("cpack");
doc.SetSection("Name", cmDocumentationName);
doc.SetSection("Usage", cmDocumentationUsage);
doc.PrependSection("Options", cmDocumentationOptions);
-
- std::vector<cmDocumentationEntry> v;
- for (auto const& g : generators.GetGeneratorsList()) {
- cmDocumentationEntry e;
- e.Name = g.first;
- e.Brief = g.second;
- v.push_back(std::move(e));
- }
- doc.SetSection("Generators", v);
-
- return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
- }
-
- if (cmSystemTools::GetErrorOccurredFlag()) {
- return 1;
+ doc.SetSection("Generators", makeGeneratorDocs(generators));
+ return !doc.PrintRequestedDocumentation(std::cout);
}
- return 0;
+ return int(cmSystemTools::GetErrorOccurredFlag());
}
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index a39c52f..643bc6f 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -165,7 +165,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
if (outstring) {
*outstring = "--build-and-test requires that the generator "
"be provided using the --build-generator "
- "command line option. ";
+ "command line option.\n";
}
return 1;
}
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 66c30c0..c6387ab 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -671,10 +671,10 @@ bool cmCTestBuildHandler::IsLaunchedWarningFile(const char* fname)
cmHasLiteralSuffix(fname, ".xml"));
}
-//######################################################################
-//######################################################################
-//######################################################################
-//######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
class cmCTestBuildHandler::LaunchHelper
{
@@ -963,10 +963,10 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
return result;
}
-//######################################################################
-//######################################################################
-//######################################################################
-//######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length,
size_t& tick, size_t tick_len,
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index fd20398..1f3633d 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -122,10 +122,15 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
cmakeConfigureCommand += "\"";
}
- cmakeConfigureCommand += " \"";
+ cmakeConfigureCommand += " \"-S";
cmakeConfigureCommand += source_dir;
cmakeConfigureCommand += "\"";
+ cmakeConfigureCommand += " \"-B";
+ cmakeConfigureCommand +=
+ this->CTest->GetCTestConfiguration("BuildDirectory");
+ cmakeConfigureCommand += "\"";
+
this->CTest->SetCTestConfiguration("ConfigureCommand",
cmakeConfigureCommand, this->Quiet);
} else {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index f7c6a9c..5c48cbf 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -73,6 +73,7 @@ public:
bool StartProcess()
{
std::vector<const char*> args;
+ args.reserve(this->CommandLineStrings.size());
for (std::string const& cl : this->CommandLineStrings) {
args.push_back(cl.c_str());
}
diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx
index 69c5793..13b0278 100644
--- a/Source/CTest/cmCTestCurl.cxx
+++ b/Source/CTest/cmCTestCurl.cxx
@@ -112,14 +112,12 @@ bool cmCTestCurl::UploadFile(std::string const& local_file,
{
response.clear();
if (!this->InitCurl()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed\n");
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");
@@ -176,7 +174,7 @@ bool cmCTestCurl::UploadFile(std::string const& local_file,
if (response.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"No response from server.\n"
- << curlDebug);
+ << curlDebug << std::endl);
return false;
}
return true;
@@ -192,7 +190,7 @@ bool cmCTestCurl::HttpRequest(std::string const& url,
<< "fields " << fields << "\n",
this->Quiet);
if (!this->InitCurl()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed");
+ cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed\n");
return false;
}
curl_easy_setopt(this->Curl, CURLOPT_POST, 1);
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
index 1c292c7..dd69968 100644
--- a/Source/CTest/cmCTestGenericHandler.cxx
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -26,13 +26,8 @@ namespace {
* is non-null, otherwise removing key `op` (if it exists).
*/
void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
- const std::string& op, const char* value)
+ const std::string& op, const std::string& value)
{
- if (!value) {
- map.erase(op);
- return;
- }
-
map[op] = value;
}
void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
@@ -47,7 +42,8 @@ void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
}
}
-void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
+void cmCTestGenericHandler::SetOption(const std::string& op,
+ const std::string& value)
{
SetMapValue(this->Options, op, value);
}
@@ -57,7 +53,7 @@ void cmCTestGenericHandler::SetOption(const std::string& op, cmValue value)
}
void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
- const char* value)
+ const std::string& value)
{
this->SetOption(op, value);
SetMapValue(this->PersistentOptions, op, value);
@@ -121,7 +117,7 @@ bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
if (!name) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create resulting XML file without providing the name"
- << std::endl;);
+ << std::endl);
return false;
}
std::ostringstream ostr;
@@ -157,7 +153,7 @@ bool cmCTestGenericHandler::StartLogFile(const char* name,
if (!name) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot create log file without providing the name"
- << std::endl;);
+ << std::endl);
return false;
}
std::ostringstream ostr;
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
index 4bdb9c2..a0197d6 100644
--- a/Source/CTest/cmCTestGenericHandler.h
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -85,17 +85,9 @@ public:
* 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 SetPersistentOption(const std::string& op, const std::string& value)
- {
- this->SetPersistentOption(op, cmValue(value));
- }
+ void SetPersistentOption(const std::string& op, const std::string& value);
void SetPersistentOption(const std::string& op, cmValue value);
- void SetOption(const std::string& op, const char* value);
- void SetOption(const std::string& op, const std::string& value)
- {
- this->SetOption(op, cmValue(value));
- }
+ void SetOption(const std::string& op, const std::string& value);
void SetOption(const std::string& op, cmValue value);
cmValue GetOption(const std::string& op);
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index be952cd..c377d68 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -143,7 +143,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
"BuildDirectory", cmSystemTools::CollapseFullPath(bdir), this->Quiet);
} else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "CTEST_BINARY_DIRECTORY not set" << std::endl;);
+ "CTEST_BINARY_DIRECTORY not set" << std::endl);
}
}
if (!this->Source.empty()) {
@@ -164,7 +164,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet);
}
- cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;);
+ cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl);
cmCTestGenericHandler* handler = this->InitializeHandler();
if (!handler) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 5a66f82..ee06b29 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -326,10 +326,6 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg)
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(); });
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index da085a6..3ff8c8f 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -223,8 +223,6 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
submitInactivityTimeout);
}
- /* HTTP PUT please */
- ::curl_easy_setopt(curl, CURLOPT_PUT, 1);
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
@@ -718,7 +716,7 @@ int cmCTestSubmitHandler::ProcessHandler()
cmValue cdashUploadFile = this->GetOption("CDashUploadFile");
cmValue cdashUploadType = this->GetOption("CDashUploadType");
if (cdashUploadFile && cdashUploadType) {
- return this->HandleCDashUploadFile(cdashUploadFile, cdashUploadType);
+ return this->HandleCDashUploadFile(*cdashUploadFile, *cdashUploadType);
}
const std::string& buildDirectory =
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index daaf5fd..1c8c713 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -363,10 +363,10 @@ void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
cmValue dval = mf->GetDefinition("CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION");
if (dval) {
- if (!this->SetTestOutputTruncation(dval)) {
+ if (!this->SetTestOutputTruncation(*dval)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Invalid value for CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION: "
- << dval << std::endl);
+ << *dval << std::endl);
}
}
}
@@ -520,7 +520,7 @@ bool cmCTestTestHandler::ProcessOptions()
if (cmValue repeat = this->GetOption("Repeat")) {
cmsys::RegularExpression repeatRegex(
"^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$");
- if (repeatRegex.find(repeat)) {
+ if (repeatRegex.find(*repeat)) {
std::string const& count = repeatRegex.match(2);
unsigned long n = 1;
cmStrToULong(count, &n); // regex guarantees success
@@ -537,12 +537,13 @@ bool cmCTestTestHandler::ProcessOptions()
}
} else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Repeat option invalid value: " << repeat << std::endl);
+ "Repeat option invalid value: " << *repeat << std::endl);
return false;
}
}
if (this->GetOption("ParallelLevel")) {
- this->CTest->SetParallelLevel(std::stoi(this->GetOption("ParallelLevel")));
+ this->CTest->SetParallelLevel(
+ std::stoi(*this->GetOption("ParallelLevel")));
}
if (this->GetOption("StopOnFailure")) {
@@ -556,12 +557,12 @@ bool cmCTestTestHandler::ProcessOptions()
cmValue val = this->GetOption("IncludeRegularExpression");
if (val) {
this->UseIncludeRegExp();
- this->SetIncludeRegExp(val);
+ this->SetIncludeRegExp(*val);
}
val = this->GetOption("ExcludeRegularExpression");
if (val) {
this->UseExcludeRegExp();
- this->SetExcludeRegExp(val);
+ this->SetExcludeRegExp(*val);
}
val = this->GetOption("ExcludeFixtureRegularExpression");
if (val) {
@@ -2110,9 +2111,9 @@ void cmCTestTestHandler::SetTestsToRunInformation(cmValue in)
this->TestsToRunString = *in;
// if the argument is a file, then read it and use the contents as the
// string
- if (cmSystemTools::FileExists(in)) {
+ if (cmSystemTools::FileExists(*in)) {
cmsys::ifstream fin(in->c_str());
- unsigned long filelen = cmSystemTools::FileLength(in);
+ unsigned long filelen = cmSystemTools::FileLength(*in);
auto buff = cm::make_unique<char[]>(filelen + 1);
fin.getline(buff.get(), filelen);
buff[fin.gcount()] = 0;
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index d448c76..045eb84 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -123,7 +123,7 @@ int cmCTestUpdateHandler::ProcessHandler()
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
- " Updating the repository: " << sourceDirectory
+ " Updating the repository: " << *sourceDirectory
<< std::endl,
this->Quiet);
@@ -163,7 +163,7 @@ int cmCTestUpdateHandler::ProcessHandler()
break;
}
vc->SetCommandLineTool(this->UpdateCommand);
- vc->SetSourceDirectory(sourceDirectory);
+ vc->SetSourceDirectory(*sourceDirectory);
// Cleanup the working tree.
vc->Cleanup();
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
index 17318a3..0fee7ac 100644
--- a/Source/Checks/Curses/CMakeLists.txt
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -1,7 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
-if(POLICY CMP0060)
- cmake_policy(SET CMP0060 NEW)
-endif()
+cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
project(CheckCurses C)
set(CURSES_NEED_NCURSES TRUE)
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 1f7776c..18c1a80 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -16,45 +16,38 @@
#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
#include "cmDocumentation.h"
-#include "cmDocumentationEntry.h" // IWYU pragma: keep
+#include "cmDocumentationEntry.h"
#include "cmMessageMetadata.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"
-static const char* cmDocumentationName[][2] = {
- { nullptr, " ccmake - Curses Interface for CMake." },
- { nullptr, nullptr }
+namespace {
+const cmDocumentationEntry cmDocumentationName = {
+ {},
+ " ccmake - Curses Interface for CMake."
};
-static const char* cmDocumentationUsage[][2] = {
- { nullptr,
+const cmDocumentationEntry cmDocumentationUsage[2] = {
+ { {},
" ccmake <path-to-source>\n"
" ccmake <path-to-existing-build>" },
- { nullptr,
+ { {},
"Specify a source directory to (re-)generate a build system for "
"it in the current working directory. Specify an existing build "
"directory to re-generate its build system." },
- { nullptr, nullptr }
};
-static const char* cmDocumentationUsageNote[][2] = {
- { nullptr, "Run 'ccmake --help' for more information." },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationUsageNote = {
+ {},
+ "Run 'ccmake --help' for more information."
};
-static const char* cmDocumentationOptions[][2] = {
- CMAKE_STANDARD_OPTIONS_TABLE,
- { nullptr, nullptr }
-};
-
-cmCursesForm* cmCursesForm::CurrentForm = nullptr;
-
#ifndef _WIN32
extern "C" {
-static void onsig(int /*unused*/)
+void onsig(int /*unused*/)
{
if (cmCursesForm::CurrentForm) {
cmCursesForm::CurrentForm->HandleResize();
@@ -63,6 +56,9 @@ static void onsig(int /*unused*/)
}
}
#endif // _WIN32
+} // anonymous namespace
+
+cmCursesForm* cmCursesForm::CurrentForm = nullptr;
int main(int argc, char const* const* argv)
{
@@ -77,7 +73,7 @@ int main(int argc, char const* const* argv)
cmDocumentation doc;
doc.addCMakeStandardDocSections();
if (doc.CheckOptions(argc, argv)) {
- cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ cmake hcm(cmake::RoleInternal, cmState::Help);
hcm.SetHomeDirectory("");
hcm.SetHomeOutputDirectory("");
hcm.AddCMakePaths();
@@ -89,8 +85,8 @@ int main(int argc, char const* const* argv)
doc.AppendSection("Usage", cmDocumentationUsageNote);
}
doc.AppendSection("Generators", generators);
- doc.PrependSection("Options", cmDocumentationOptions);
- return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE);
+ return !doc.PrintRequestedDocumentation(std::cout);
}
bool debug = false;
diff --git a/Source/CursesDialog/form/.gitattributes b/Source/CursesDialog/form/.gitattributes
index 6dfa627..6e255e4 100644
--- a/Source/CursesDialog/form/.gitattributes
+++ b/Source/CursesDialog/form/.gitattributes
@@ -1,2 +1,2 @@
* -whitespace
-* -format.clang-format-6.0
+* -format.clang-format
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index fb12b7d..50e8e3a 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -22,26 +22,27 @@
#include "cmSystemTools.h" // IWYU pragma: keep
#include "cmake.h"
-static const char* cmDocumentationName[][2] = { { nullptr,
- " cmake-gui - CMake GUI." },
- { nullptr, nullptr } };
-
-static const char* cmDocumentationUsage[][2] = {
- { nullptr,
- " cmake-gui [options]\n"
- " cmake-gui [options] <path-to-source>\n"
- " cmake-gui [options] <path-to-existing-build>\n"
- " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n"
- " cmake-gui [options] --browse-manual\n" },
- { nullptr, nullptr }
+namespace {
+const cmDocumentationEntry cmDocumentationName = {
+ {},
+ " cmake-gui - CMake GUI."
};
-static const char* cmDocumentationOptions[][2] = {
+const cmDocumentationEntry cmDocumentationUsage = {
+ {},
+ " cmake-gui [options]\n"
+ " cmake-gui [options] <path-to-source>\n"
+ " cmake-gui [options] <path-to-existing-build>\n"
+ " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n"
+ " cmake-gui [options] --browse-manual"
+};
+
+const cmDocumentationEntry cmDocumentationOptions[3] = {
{ "-S <path-to-source>", "Explicitly specify a source directory." },
{ "-B <path-to-build>", "Explicitly specify a build directory." },
- { "--preset=<preset>", "Specify a configure preset." },
- { nullptr, nullptr }
+ { "--preset=<preset>", "Specify a configure preset." }
};
+} // anonymous namespace
#if defined(Q_OS_MAC)
static int cmOSXInstall(std::string dir);
@@ -79,7 +80,7 @@ int main(int argc, char** argv)
doc.addCMakeStandardDocSections();
if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
// Construct and print requested documentation.
- cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ cmake hcm(cmake::RoleInternal, cmState::Help);
hcm.SetHomeDirectory("");
hcm.SetHomeOutputDirectory("");
hcm.AddCMakePaths();
@@ -91,7 +92,7 @@ int main(int argc, char** argv)
doc.AppendSection("Generators", generators);
doc.PrependSection("Options", cmDocumentationOptions);
- return (doc.PrintRequestedDocumentation(std::cout) ? 0 : 1);
+ return !doc.PrintRequestedDocumentation(std::cout);
}
#if defined(Q_OS_MAC)
@@ -252,6 +253,7 @@ int main(int argc, char** argv)
# include <unistd.h>
# include "cm_sys_stat.h"
+
static bool cmOSXInstall(std::string const& dir, std::string const& tool)
{
if (tool.empty()) {
@@ -277,6 +279,7 @@ static bool cmOSXInstall(std::string const& dir, std::string const& tool)
<< "': " << strerror(err) << "\n";
return false;
}
+
static int cmOSXInstall(std::string dir)
{
if (!cmHasLiteralSuffix(dir, "/")) {
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index 01fa7bb..3d4d726 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -1344,7 +1344,8 @@ void CMakeSetupDialog::showUserChanges()
void CMakeSetupDialog::setSearchFilter(const QString& str)
{
this->CacheValues->selectionModel()->clear();
- this->CacheValues->setSearchFilter(str);
+ const bool valid = this->CacheValues->setSearchFilter(str);
+ QtCMake::setSearchFilterColor(this->Search, valid);
}
void CMakeSetupDialog::doOutputContextMenu(QPoint pt)
diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx
index bf89816..2752c0f 100644
--- a/Source/QtDialog/EnvironmentDialog.cxx
+++ b/Source/QtDialog/EnvironmentDialog.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "EnvironmentDialog.h"
+#include "QCMakeWidgets.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QItemSelectionModel>
@@ -110,14 +111,11 @@ EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment,
&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->Search, &QLineEdit::textChanged, [this](const QString& text) {
+ const bool valid = QtCMake::setSearchFilter(this->m_filter, text);
+ QtCMake::setSearchFilterColor(this->Search, valid);
+ });
QObject::connect(this->Environment->selectionModel(),
&QItemSelectionModel::selectionChanged, this,
&EnvironmentDialog::selectionChanged);
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
index f79d6fc..6f19b67 100644
--- a/Source/QtDialog/QCMakeCacheView.cxx
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -167,13 +167,9 @@ bool QCMakeCacheView::showAdvanced() const
return this->AdvancedFilter->showAdvanced();
}
-void QCMakeCacheView::setSearchFilter(const QString& s)
+bool QCMakeCacheView::setSearchFilter(const QString& s)
{
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
- this->SearchFilter->setFilterRegularExpression(s);
-#else
- this->SearchFilter->setFilterFixedString(s);
-#endif
+ return QtCMake::setSearchFilter(this->SearchFilter, s);
}
QCMakeCacheModel::QCMakeCacheModel(QObject* p)
diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h
index c5e6dd4..89068ab 100644
--- a/Source/QtDialog/QCMakeCacheView.h
+++ b/Source/QtDialog/QCMakeCacheView.h
@@ -28,12 +28,13 @@ public:
QSize sizeHint() const { return QSize(200, 200); }
+ // set the search filter string. any property key or value not matching will
+ // be filtered out
+ bool setSearchFilter(const QString&);
+
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);
diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx
index 03d6ed1..f1bb2f1 100644
--- a/Source/QtDialog/QCMakeWidgets.cxx
+++ b/Source/QtDialog/QCMakeWidgets.cxx
@@ -10,8 +10,13 @@
#include <QFileDialog>
#include <QFileInfo>
#include <QResizeEvent>
+#include <QSortFilterProxyModel>
#include <QToolButton>
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+# include <QRegularExpression>
+#endif
+
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include <QFileSystemModel>
#else
@@ -155,3 +160,32 @@ QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const
{
return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx));
}
+
+namespace QtCMake {
+bool setSearchFilter(QSortFilterProxyModel* model, const QString& searchString)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
+ QRegularExpression const regex(searchString,
+ QRegularExpression::CaseInsensitiveOption |
+ QRegularExpression::DontCaptureOption);
+ if (regex.isValid()) {
+ model->setFilterRegularExpression(regex);
+ return true;
+ }
+ model->setFilterFixedString(QString{});
+ return false;
+#else
+ model->setFilterFixedString(searchString);
+ return true;
+#endif
+}
+
+void setSearchFilterColor(QLineEdit* edit, bool valid)
+{
+ QPalette palette;
+ if (!valid) {
+ palette.setColor(QPalette::Base, Qt::red);
+ }
+ edit->setPalette(palette);
+}
+}
diff --git a/Source/QtDialog/QCMakeWidgets.h b/Source/QtDialog/QCMakeWidgets.h
index 9a2a27e..858a913 100644
--- a/Source/QtDialog/QCMakeWidgets.h
+++ b/Source/QtDialog/QCMakeWidgets.h
@@ -9,6 +9,7 @@
#include <QLineEdit>
class QToolButton;
+class QSortFilterProxyModel;
// common widgets for Qt based CMake
@@ -76,3 +77,10 @@ public:
}
}
};
+
+namespace QtCMake {
+bool setSearchFilter(QSortFilterProxyModel* model,
+ const QString& searchString);
+
+void setSearchFilterColor(QLineEdit* edit, bool valid);
+}
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index f29983c..e992b4b 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -68,7 +68,7 @@ public:
~Entry() { archive_entry_free(this->Object); }
Entry(const Entry&) = delete;
Entry& operator=(const Entry&) = delete;
- operator struct archive_entry*() { return this->Object; }
+ operator struct archive_entry *() { return this->Object; }
};
struct cmArchiveWrite::Callback
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index a69c00d..5972202 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -154,8 +154,13 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
if (!this->Archive->IsPostExcluded(path)) {
bool unique;
this->Archive->AddResolvedPath(dep, path, unique);
- if (unique && !this->ScanDependencies(path, rpaths)) {
- return false;
+ if (unique) {
+ std::vector<std::string> combinedParentRpaths = parentRpaths;
+ combinedParentRpaths.insert(combinedParentRpaths.end(),
+ rpaths.begin(), rpaths.end());
+ if (!this->ScanDependencies(path, combinedParentRpaths)) {
+ return false;
+ }
}
}
} else {
diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h
index 9e47a69..2726e92 100644
--- a/Source/cmCMakePresetsGraphInternal.h
+++ b/Source/cmCMakePresetsGraphInternal.h
@@ -1,5 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
#include <memory>
#include <string>
#include <vector>
diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx
index eec53c1..a96ab58 100644
--- a/Source/cmCMakePresetsGraphReadJSON.cxx
+++ b/Source/cmCMakePresetsGraphReadJSON.cxx
@@ -518,9 +518,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
PresetPair<ConfigurePreset> presetPair;
presetPair.Unexpanded = preset;
presetPair.Expanded = cm::nullopt;
- if (!this->ConfigurePresets
- .emplace(std::make_pair(preset.Name, presetPair))
- .second) {
+ if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) {
return ReadFileResult::DUPLICATE_PRESETS;
}
diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h
index 19626f0..13a93b7 100644
--- a/Source/cmCPluginAPI.h
+++ b/Source/cmCPluginAPI.h
@@ -8,7 +8,7 @@
loosely into four groups 1) Utility 2) cmMakefile 3) cmSourceFile 4)
cmSystemTools. Within each grouping functions are listed alphabetically */
/*=========================================================================*/
-#ifndef cmCPluginAPI_h
+#ifndef cmCPluginAPI_h /* NOLINT(cmake-use-pragma-once) */
#define cmCPluginAPI_h
#define CMAKE_VERSION_MAJOR 2
@@ -201,7 +201,7 @@ 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* []);
+ char*[]);
/* NOLINTNEXTLINE(modernize-use-using) */
typedef void(CCONV* CM_FINAL_PASS_FUNCTION)(void* info, void* mf);
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index f60a1e9..5899a61 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -217,6 +217,7 @@ struct cmCTest::Private
std::map<std::string, std::string> Definitions;
cmCTest::NoTests NoTestsMode = cmCTest::NoTests::Legacy;
+ bool NoTestsModeSetInCli = false;
};
struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
@@ -410,7 +411,8 @@ cmCTest::Part cmCTest::GetPartFromName(const std::string& name)
return PartCount;
}
-int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command)
+int cmCTest::Initialize(const std::string& binary_dir,
+ cmCTestStartCommand* command)
{
bool quiet = false;
if (command && command->ShouldBeQuiet()) {
@@ -683,7 +685,7 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
this->SetCTestConfigurationFromCMakeVariable(
mf, "BuildName", "CTEST_BUILD_NAME", command->ShouldBeQuiet());
- if (!this->Initialize(bld_dir.c_str(), command)) {
+ if (!this->Initialize(bld_dir, command)) {
return false;
}
cmCTestOptionalLog(this, OUTPUT,
@@ -943,8 +945,7 @@ int cmCTest::ProcessSteps()
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
uphandler->SetPersistentOption(
- "SourceDirectory",
- this->GetCTestConfiguration("SourceDirectory").c_str());
+ "SourceDirectory", this->GetCTestConfiguration("SourceDirectory"));
update_count = uphandler->ProcessHandler();
if (update_count < 0) {
res |= cmCTest::UPDATE_ERRORS;
@@ -1065,10 +1066,10 @@ int cmCTest::GetTestModelFromString(const std::string& str)
return cmCTest::EXPERIMENTAL;
}
-//######################################################################
-//######################################################################
-//######################################################################
-//######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
int* retVal, const char* dir, cmDuration timeout,
@@ -1184,10 +1185,10 @@ int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
return result;
}
-//######################################################################
-//######################################################################
-//######################################################################
-//######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
+// ######################################################################
int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
int* retVal, std::ostream* log, cmDuration testTimeOut,
@@ -1691,7 +1692,7 @@ bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files)
if (!cmSystemTools::FileExists(file)) {
cmCTestLog(this, ERROR_MESSAGE,
"Cannot find extra file: " << file << " to submit."
- << std::endl;);
+ << std::endl);
return false;
}
this->AddSubmitFile(PartExtraFiles, file);
@@ -2132,6 +2133,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
} else {
this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
}
+ this->Impl->NoTestsModeSetInCli = true;
}
// options that control what tests are run
@@ -2139,9 +2141,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
- args[i].c_str());
+ args[i]);
this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
- args[i].c_str());
+ args[i]);
} else if (this->CheckArgument(arg, "-U"_s, "--union")) {
this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
@@ -2149,9 +2151,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
- args[i].c_str());
+ args[i]);
this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
- args[i].c_str());
+ args[i]);
} else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
i < args.size() - 1) {
i++;
@@ -2172,41 +2174,40 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
- args[i].c_str());
+ args[i]);
this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
- args[i].c_str());
+ args[i]);
}
else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") &&
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureRegularExpression", args[i].c_str());
+ "ExcludeFixtureRegularExpression", args[i]);
this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureRegularExpression", args[i].c_str());
+ "ExcludeFixtureRegularExpression", args[i]);
} else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") &&
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ "ExcludeFixtureSetupRegularExpression", args[i]);
this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureSetupRegularExpression", args[i].c_str());
+ "ExcludeFixtureSetupRegularExpression", args[i]);
} else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") &&
i < args.size() - 1) {
i++;
this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ "ExcludeFixtureCleanupRegularExpression", args[i]);
this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
+ "ExcludeFixtureCleanupRegularExpression", args[i]);
}
else if (this->CheckArgument(arg, "--resource-spec-file"_s) &&
i < args.size() - 1) {
i++;
- this->GetTestHandler()->SetPersistentOption("ResourceSpecFile",
- args[i].c_str());
+ this->GetTestHandler()->SetPersistentOption("ResourceSpecFile", args[i]);
this->GetMemCheckHandler()->SetPersistentOption("ResourceSpecFile",
- args[i].c_str());
+ args[i]);
}
else if (this->CheckArgument(arg, "--rerun-failed"_s)) {
@@ -2314,8 +2315,8 @@ 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());
+ this->GetTestHandler()->SetPersistentOption(optionName, value);
+ this->GetMemCheckHandler()->SetPersistentOption(optionName, value);
}
}
@@ -2758,8 +2759,9 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
// 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");
+ cmCTestLog(
+ this, ERROR_MESSAGE,
+ "Problem parsing command line arguments within a handler\n");
return 0;
}
}
@@ -2774,6 +2776,24 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output)
}
}
+ // handle CTEST_NO_TESTS_ACTION environment variable
+ if (!this->Impl->NoTestsModeSetInCli) {
+ std::string action;
+ if (cmSystemTools::GetEnv("CTEST_NO_TESTS_ACTION", action) &&
+ !action.empty()) {
+ if (action == "error"_s) {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+ } else if (action == "ignore"_s) {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+ } else {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Unknown value for CTEST_NO_TESTS_ACTION: '" << action
+ << '\'');
+ return 1;
+ }
+ }
+ }
+
// TestProgressOutput only supported if console supports it and not logging
// to a file
this->Impl->TestProgressOutput = this->Impl->TestProgressOutput &&
@@ -2903,7 +2923,7 @@ int cmCTest::ExecuteTests()
}
}
- if (!this->Initialize(workDir.c_str(), nullptr)) {
+ if (!this->Initialize(workDir, nullptr)) {
res = 12;
cmCTestLog(this, ERROR_MESSAGE,
"Problem initializing the dashboard." << std::endl);
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 0017b3e..9a8d5a6 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -481,7 +481,7 @@ private:
* 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);
+ int Initialize(const std::string& binary_dir, cmCTestStartCommand* command);
/** parse the option after -D and convert it into the appropriate steps */
bool AddTestsForDashboardType(std::string& targ);
diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h
index 795b863..78f22ae 100644
--- a/Source/cmCallVisualStudioMacro.h
+++ b/Source/cmCallVisualStudioMacro.h
@@ -19,8 +19,7 @@ public:
//! 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);
+ const std::string& args, bool logErrorsAsMessages);
//! Count the number of running instances of Visual Studio with the
//! given solution file open. Pass "ALL" for slnFile to count all
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
index 33c91bc..003e972 100644
--- a/Source/cmCommandLineArgument.h
+++ b/Source/cmCommandLineArgument.h
@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
+#include <cm/optional>
+
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -250,6 +252,15 @@ private:
return true;
};
}
+
+ static std::function<bool(const std::string&, CallState...)>
+ generateSetToValue(cm::optional<std::string>& value1)
+ {
+ return [&value1](const std::string& arg, CallState&&...) -> bool {
+ value1 = arg;
+ return true;
+ };
+ }
};
std::string extract_single_value(std::string const& input,
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 5fe6756..a065ba9 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -6,6 +6,9 @@
#include <sstream>
#include <utility>
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalCommonGenerator.h"
@@ -157,7 +160,7 @@ std::string cmCommonTargetGenerator::GetIncludes(std::string const& l,
}
std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
- const std::string& config) const
+ const std::string& lang, const std::string& config) const
{
std::vector<std::string> dirs;
std::set<cmGeneratorTarget const*> emitted;
@@ -172,6 +175,8 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories(
// Target->GetLinkInformation already processed their
// link interface and they don't have any output themselves.
&& linkee->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
+ ((lang == "CXX"_s && linkee->HaveCxx20ModuleSources()) ||
+ (lang == "Fortran"_s && linkee->HaveFortranSources(config))) &&
emitted.insert(linkee).second) {
cmLocalGenerator* lg = linkee->GetLocalGenerator();
std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
index e8c5a19..2d23037 100644
--- a/Source/cmCommonTargetGenerator.h
+++ b/Source/cmCommonTargetGenerator.h
@@ -65,7 +65,7 @@ protected:
std::string GetAIXExports(std::string const& config);
std::vector<std::string> GetLinkedTargetDirectories(
- const std::string& config) const;
+ const std::string& lang, const std::string& config) const;
std::string ComputeTargetCompilePDB(const std::string& config) const;
std::string GetLinkerLauncher(const std::string& config);
diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx
index 6591fb1..16540c3 100644
--- a/Source/cmComputeComponentGraph.cxx
+++ b/Source/cmComputeComponentGraph.cxx
@@ -4,6 +4,11 @@
#include <algorithm>
#include <cassert>
+#include <cstddef>
+#include <limits>
+
+const size_t cmComputeComponentGraph::INVALID_COMPONENT =
+ std::numeric_limits<size_t>::max();
cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input)
: InputGraph(input)
@@ -25,16 +30,16 @@ void cmComputeComponentGraph::Compute()
void cmComputeComponentGraph::Tarjan()
{
- int n = static_cast<int>(this->InputGraph.size());
+ size_t n = 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->TarjanComponents.resize(n, INVALID_COMPONENT);
this->TarjanWalkId = 0;
this->TarjanVisited.resize(0);
this->TarjanVisited.resize(n, 0);
- for (int i = 0; i < n; ++i) {
+ for (size_t 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());
@@ -45,21 +50,21 @@ void cmComputeComponentGraph::Tarjan()
}
}
-void cmComputeComponentGraph::TarjanVisit(int i)
+void cmComputeComponentGraph::TarjanVisit(size_t 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->TarjanComponents[i] = INVALID_COMPONENT;
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;
+ size_t 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
@@ -77,7 +82,7 @@ void cmComputeComponentGraph::TarjanVisit(int i)
// 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->TarjanComponents[j] == INVALID_COMPONENT) {
if (this->TarjanEntries[this->TarjanEntries[j].Root].VisitIndex <
this->TarjanEntries[this->TarjanEntries[i].Root].VisitIndex) {
this->TarjanEntries[i].Root = this->TarjanEntries[j].Root;
@@ -88,12 +93,12 @@ void cmComputeComponentGraph::TarjanVisit(int i)
// Check if we have found a component.
if (this->TarjanEntries[i].Root == i) {
// Yes. Create it.
- int c = static_cast<int>(this->Components.size());
+ size_t c = this->Components.size();
this->Components.emplace_back();
NodeList& component = this->Components[c];
// Populate the component list.
- int j;
+ size_t j;
do {
// Get the next member of the component.
j = this->TarjanStack.top();
@@ -116,13 +121,13 @@ 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];
+ size_t n = this->InputGraph.size();
+ for (size_t i = 0; i < n; ++i) {
+ size_t 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];
+ size_t j = ni;
+ size_t 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.
diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h
index 1d1d134..878e36d 100644
--- a/Source/cmComputeComponentGraph.h
+++ b/Source/cmComputeComponentGraph.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <cstddef>
#include <stack>
#include <vector>
@@ -35,7 +36,7 @@ public:
/** Get the adjacency list of the component graph. */
Graph const& GetComponentGraph() const { return this->ComponentGraph; }
- EdgeList const& GetComponentGraphEdges(int c) const
+ EdgeList const& GetComponentGraphEdges(size_t c) const
{
return this->ComponentGraph[c];
}
@@ -45,14 +46,16 @@ public:
{
return this->Components;
}
- NodeList const& GetComponent(int c) const { return this->Components[c]; }
+ NodeList const& GetComponent(size_t c) const { return this->Components[c]; }
/** Get map from original node index to component index. */
- std::vector<int> const& GetComponentMap() const
+ std::vector<size_t> const& GetComponentMap() const
{
return this->TarjanComponents;
}
+ static const size_t INVALID_COMPONENT;
+
private:
void TransferEdges();
@@ -62,18 +65,18 @@ private:
// Tarjan's algorithm.
struct TarjanEntry
{
- int Root;
- int VisitIndex;
+ size_t Root;
+ size_t VisitIndex;
};
- std::vector<int> TarjanVisited;
- std::vector<int> TarjanComponents;
+ std::vector<size_t> TarjanVisited;
+ std::vector<size_t> TarjanComponents;
std::vector<TarjanEntry> TarjanEntries;
std::vector<NodeList> Components;
- std::stack<int> TarjanStack;
- int TarjanWalkId;
- int TarjanIndex;
+ std::stack<size_t> TarjanStack;
+ size_t TarjanWalkId;
+ size_t TarjanIndex;
void Tarjan();
- void TarjanVisit(int i);
+ void TarjanVisit(size_t i);
// Connected components.
};
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 8cbdcaa..5f408d0 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -4,6 +4,7 @@
#include <algorithm>
#include <cassert>
+#include <cstddef>
#include <cstdio>
#include <iterator>
#include <sstream>
@@ -260,8 +261,8 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
"LINK_LIBRARY_OVERRIDE",
nullptr, nullptr };
auto overrideFeature = cmGeneratorExpression::Evaluate(
- feature, this->Target->GetLocalGenerator(), config, this->Target,
- &dag, this->Target, linkLanguage);
+ *feature, this->Target->GetLocalGenerator(), config,
+ this->Target, &dag, this->Target, linkLanguage);
this->LinkLibraryOverride.emplace(item, overrideFeature);
}
}
@@ -274,7 +275,7 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
"LINK_LIBRARY_OVERRIDE", nullptr,
nullptr };
auto overrideValue = cmGeneratorExpression::Evaluate(
- linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
+ *linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
target, linkLanguage);
auto overrideList = cmTokenize(overrideValue, ","_s);
@@ -375,8 +376,8 @@ cmComputeLinkDepends::Compute()
// 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)) {
+ std::set<size_t> emitted;
+ for (size_t 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.
@@ -388,7 +389,7 @@ cmComputeLinkDepends::Compute()
// Place explicitly linked object files in the front. The linker will
// always use them anyway, and they may depend on symbols from libraries.
// Append in reverse order since we reverse the final order below.
- for (int i : cmReverseRange(this->ObjectEntries)) {
+ for (size_t i : cmReverseRange(this->ObjectEntries)) {
this->FinalLinkEntries.emplace_back(this->EntryList[i]);
}
// Reverse the resulting order since we iterated in reverse.
@@ -432,11 +433,11 @@ std::string const& cmComputeLinkDepends::GetCurrentFeature(
return it == this->LinkLibraryOverride.end() ? defaultFeature : it->second;
}
-std::pair<std::map<cmLinkItem, int>::iterator, bool>
+std::pair<std::map<cmLinkItem, size_t>::iterator, bool>
cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item)
{
- std::map<cmLinkItem, int>::value_type index_entry(
- item, static_cast<int>(this->EntryList.size()));
+ std::map<cmLinkItem, size_t>::value_type index_entry(
+ item, static_cast<size_t>(this->EntryList.size()));
auto lei = this->LinkEntryIndex.insert(index_entry);
if (lei.second) {
this->EntryList.emplace_back();
@@ -446,8 +447,8 @@ cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item)
return lei;
}
-std::pair<int, bool> cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item,
- int groupIndex)
+std::pair<size_t, bool> cmComputeLinkDepends::AddLinkEntry(
+ cmLinkItem const& item, size_t groupIndex)
{
// Allocate a spot for the item entry.
auto lei = this->AllocateLinkEntry(item);
@@ -459,7 +460,7 @@ std::pair<int, bool> cmComputeLinkDepends::AddLinkEntry(cmLinkItem const& item,
}
// Initialize the item entry.
- int index = lei.first->second;
+ size_t index = lei.first->second;
LinkEntry& entry = this->EntryList[index];
entry.Item = BT<std::string>(item.AsStr(), item.Backtrace);
entry.Target = item.Target;
@@ -506,7 +507,7 @@ void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item)
}
// Initialize the item entry.
- int index = lei.first->second;
+ size_t index = lei.first->second;
LinkEntry& entry = this->EntryList[index];
entry.Item = BT<std::string>(item.AsStr(), item.Backtrace);
entry.Kind = LinkEntry::Object;
@@ -518,7 +519,10 @@ void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item)
void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe)
{
// Get this entry representation.
- int depender_index = qe.GroupIndex == -1 ? qe.Index : qe.GroupIndex;
+ size_t depender_index =
+ qe.GroupIndex == cmComputeComponentGraph::INVALID_COMPONENT
+ ? qe.Index
+ : qe.GroupIndex;
LinkEntry const& entry = this->EntryList[qe.Index];
// Follow the item's dependencies.
@@ -556,7 +560,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe)
}
}
-void cmComputeLinkDepends::FollowSharedDeps(int depender_index,
+void cmComputeLinkDepends::FollowSharedDeps(size_t depender_index,
cmLinkInterface const* iface,
bool follow_interface)
{
@@ -570,7 +574,7 @@ void cmComputeLinkDepends::FollowSharedDeps(int depender_index,
}
void cmComputeLinkDepends::QueueSharedDependencies(
- int depender_index, std::vector<cmLinkItem> const& deps)
+ size_t depender_index, std::vector<cmLinkItem> const& deps)
{
for (cmLinkItem const& li : deps) {
SharedDepEntry qe;
@@ -584,7 +588,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
{
// Allocate a spot for the item entry.
auto lei = this->AllocateLinkEntry(dep.Item);
- int index = lei.first->second;
+ size_t index = lei.first->second;
// Check if the target does not already has an entry.
if (lei.second) {
@@ -617,7 +621,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
}
}
-void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
+void cmComputeLinkDepends::AddVarLinkEntries(size_t depender_index,
const char* value)
{
// This is called to add the dependencies named by
@@ -679,13 +683,15 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
// Add direct link dependencies in this configuration.
cmLinkImplementation const* impl = this->Target->GetLinkImplementation(
this->Config, cmGeneratorTarget::LinkInterfaceFor::Link);
- this->AddLinkEntries(-1, impl->Libraries);
+ this->AddLinkEntries(cmComputeComponentGraph::INVALID_COMPONENT,
+ impl->Libraries);
this->AddLinkObjects(impl->Objects);
for (auto const& language : impl->Languages) {
auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language);
if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) {
- this->AddLinkEntries(-1, runtimeEntries->second);
+ this->AddLinkEntries(cmComputeComponentGraph::INVALID_COMPONENT,
+ runtimeEntries->second);
}
}
for (cmLinkItem const& wi : impl->WrongConfigLibraries) {
@@ -694,16 +700,18 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
}
template <typename T>
-void cmComputeLinkDepends::AddLinkEntries(int depender_index,
+void cmComputeLinkDepends::AddLinkEntries(size_t depender_index,
std::vector<T> const& libs)
{
// Track inferred dependency sets implied by this list.
- std::map<int, DependSet> dependSets;
+ std::map<size_t, DependSet> dependSets;
std::string feature = LinkEntry::DEFAULT;
bool inGroup = false;
- std::pair<int, bool> groupIndex{ -1, false };
- std::vector<int> groupItems;
+ std::pair<size_t, bool> groupIndex{
+ cmComputeComponentGraph::INVALID_COMPONENT, false
+ };
+ std::vector<size_t> groupItems;
// Loop over the libraries linked directly by the depender.
for (T const& l : libs) {
@@ -719,7 +727,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
feature = ExtractFeature(item.AsStr());
// emit a warning if an undefined feature is used as part of
// an imported target
- if (depender_index >= 0) {
+ if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) {
const auto& depender = this->EntryList[depender_index];
if (depender.Target != nullptr && depender.Target->IsImported() &&
!IsFeatureSupported(this->Makefile, this->LinkLanguage, feature)) {
@@ -752,7 +760,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
entry.Feature = ExtractGroupFeature(item.AsStr());
}
inGroup = true;
- if (depender_index >= 0) {
+ if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) {
this->EntryConstraintGraph[depender_index].emplace_back(
groupIndex.first, false, false, cmListFileBacktrace());
} else {
@@ -762,7 +770,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
continue;
}
- int dependee_index;
+ size_t dependee_index;
if (cmHasPrefix(item.AsStr(), LG_END) && cmHasSuffix(item.AsStr(), '>')) {
dependee_index = groupIndex.first;
@@ -775,7 +783,8 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
continue;
}
- if (depender_index >= 0 && inGroup) {
+ if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT &&
+ inGroup) {
const auto& depender = this->EntryList[depender_index];
const auto& groupFeature = this->EntryList[groupIndex.first].Feature;
if (depender.Target != nullptr && depender.Target->IsImported() &&
@@ -895,7 +904,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
// store item index for dependencies handling
groupItems.push_back(dependee_index);
} else {
- std::vector<int> indexes;
+ std::vector<size_t> indexes;
bool entryHandled = false;
// search any occurrence of the library in already defined groups
for (const auto& group : this->GroupItems) {
@@ -913,7 +922,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index,
for (auto index : indexes) {
// The dependee must come after the depender.
- if (depender_index >= 0) {
+ if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) {
this->EntryConstraintGraph[depender_index].emplace_back(
index, false, false, cmListFileBacktrace());
} else {
@@ -957,12 +966,12 @@ void cmComputeLinkDepends::AddLinkObjects(std::vector<cmLinkItem> const& objs)
}
}
-cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index,
+cmLinkItem cmComputeLinkDepends::ResolveLinkItem(size_t 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 (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) {
if (cmGeneratorTarget const* depender =
this->EntryList[depender_index].Target) {
from = depender;
@@ -976,7 +985,7 @@ 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;
+ for (size_t 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.
@@ -1013,7 +1022,7 @@ void cmComputeLinkDepends::UpdateGroupDependencies()
// over raw items by the group it belongs to, if any.
for (auto& edgeList : this->EntryConstraintGraph) {
for (auto& edge : edgeList) {
- int index = edge;
+ size_t index = edge;
if (this->EntryList[index].Kind == LinkEntry::Group ||
this->EntryList[index].Kind == LinkEntry::Flag ||
this->EntryList[index].Kind == LinkEntry::Object) {
@@ -1049,8 +1058,8 @@ void cmComputeLinkDepends::CleanConstraintGraph()
bool cmComputeLinkDepends::CheckCircularDependencies() const
{
std::vector<NodeList> const& components = this->CCG->GetComponents();
- int nc = static_cast<int>(components.size());
- for (int c = 0; c < nc; ++c) {
+ size_t nc = components.size();
+ for (size_t c = 0; c < nc; ++c) {
// Get the current component.
NodeList const& nl = components[c];
@@ -1061,7 +1070,7 @@ bool cmComputeLinkDepends::CheckCircularDependencies() const
// no group must be evolved
bool cycleDetected = false;
- for (int ni : nl) {
+ for (size_t ni : nl) {
if (this->EntryList[ni].Kind == LinkEntry::Group) {
cycleDetected = true;
break;
@@ -1089,8 +1098,8 @@ bool cmComputeLinkDepends::CheckCircularDependencies() const
<< this->Target->GetName()
<< "\", contains the following strongly connected component "
"(cycle):\n";
- std::vector<int> const& cmap = this->CCG->GetComponentMap();
- for (int i : nl) {
+ std::vector<size_t> const& cmap = this->CCG->GetComponentMap();
+ for (size_t i : nl) {
// Get the depender.
LinkEntry const& depender = this->EntryList[i];
@@ -1100,7 +1109,7 @@ bool cmComputeLinkDepends::CheckCircularDependencies() const
// List its dependencies that are inside the component.
EdgeList const& el = this->EntryConstraintGraph[i];
for (cmGraphEdge const& ni : el) {
- int j = ni;
+ size_t j = ni;
if (cmap[j] == c) {
LinkEntry const& dependee = this->EntryList[j];
e << " depends on " << formatItem(dependee) << "\n";
@@ -1120,7 +1129,7 @@ void cmComputeLinkDepends::DisplayConstraintGraph()
{
// Display the graph nodes and their edges.
std::ostringstream e;
- for (unsigned int i = 0; i < this->EntryConstraintGraph.size(); ++i) {
+ for (size_t 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";
@@ -1134,13 +1143,14 @@ void cmComputeLinkDepends::OrderLinkEntries()
// from every entry to compute a topological order for the
// components.
Graph const& cgraph = this->CCG->GetComponentGraph();
- int n = static_cast<int>(cgraph.size());
+ size_t n = 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) {
+ for (size_t c = n - 1; c != cmComputeComponentGraph::INVALID_COMPONENT;
+ --c) {
this->VisitComponent(c);
}
@@ -1150,7 +1160,7 @@ void cmComputeLinkDepends::OrderLinkEntries()
}
// Start with the original link line.
- for (int originalEntry : this->OriginalEntries) {
+ for (size_t originalEntry : this->OriginalEntries) {
this->VisitEntry(originalEntry);
}
@@ -1161,7 +1171,7 @@ void cmComputeLinkDepends::OrderLinkEntries()
// 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();
+ size_t e = *this->PendingComponents.begin()->second.Entries.begin();
this->VisitEntry(e);
}
}
@@ -1170,24 +1180,24 @@ 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);
+ for (size_t c = 0; c < components.size(); ++c) {
+ fprintf(stderr, "Component (%zu):\n", c);
NodeList const& nl = components[c];
- for (int i : nl) {
- fprintf(stderr, " item %d [%s]\n", i,
+ for (size_t i : nl) {
+ fprintf(stderr, " item %zu [%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);
+ size_t i = oi;
+ fprintf(stderr, " followed by Component (%zu)\n", i);
}
- fprintf(stderr, " topo order index %d\n", this->ComponentOrder[c]);
+ fprintf(stderr, " topo order index %zu\n", this->ComponentOrder[c]);
}
fprintf(stderr, "\n");
}
-void cmComputeLinkDepends::VisitComponent(unsigned int c)
+void cmComputeLinkDepends::VisitComponent(size_t c)
{
// Check if the node has already been visited.
if (this->ComponentVisited[c]) {
@@ -1209,14 +1219,14 @@ void cmComputeLinkDepends::VisitComponent(unsigned int c)
this->ComponentOrder[c] = --this->ComponentOrderId;
}
-void cmComputeLinkDepends::VisitEntry(int index)
+void cmComputeLinkDepends::VisitEntry(size_t 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];
+ size_t 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.
@@ -1267,7 +1277,7 @@ void cmComputeLinkDepends::VisitEntry(int index)
}
cmComputeLinkDepends::PendingComponent&
-cmComputeLinkDepends::MakePendingComponent(unsigned int component)
+cmComputeLinkDepends::MakePendingComponent(size_t component)
{
// Create an entry (in topological order) for the component.
PendingComponent& pc =
@@ -1300,10 +1310,10 @@ cmComputeLinkDepends::MakePendingComponent(unsigned int component)
return pc;
}
-int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
+size_t cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
{
- unsigned int count = 2;
- for (int ni : nl) {
+ size_t count = 2;
+ for (size_t ni : nl) {
if (cmGeneratorTarget const* target = this->EntryList[ni].Target) {
if (cmLinkInterface const* iface =
target->GetLinkInterface(this->Config, this->Target)) {
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index 8cc916a..22c4e2a 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <cstddef>
#include <map>
#include <memory>
#include <queue>
@@ -12,12 +13,12 @@
#include <utility>
#include <vector>
+#include "cmComputeComponentGraph.h"
#include "cmGraphAdjacencyList.h"
#include "cmLinkItem.h"
#include "cmListFileCache.h"
#include "cmTargetLinkLibraryType.h"
-class cmComputeComponentGraph;
class cmGeneratorTarget;
class cmGlobalGenerator;
class cmMakefile;
@@ -91,30 +92,31 @@ private:
std::string const& GetCurrentFeature(
std::string const& item, std::string const& defaultFeature) const;
- std::pair<std::map<cmLinkItem, int>::iterator, bool> AllocateLinkEntry(
+ std::pair<std::map<cmLinkItem, size_t>::iterator, bool> AllocateLinkEntry(
cmLinkItem const& item);
- std::pair<int, bool> AddLinkEntry(cmLinkItem const& item,
- int groupIndex = -1);
+ std::pair<size_t, bool> AddLinkEntry(
+ cmLinkItem const& item,
+ size_t groupIndex = cmComputeComponentGraph::INVALID_COMPONENT);
void AddLinkObject(cmLinkItem const& item);
- void AddVarLinkEntries(int depender_index, const char* value);
+ void AddVarLinkEntries(size_t depender_index, const char* value);
void AddDirectLinkEntries();
template <typename T>
- void AddLinkEntries(int depender_index, std::vector<T> const& libs);
+ void AddLinkEntries(size_t depender_index, std::vector<T> const& libs);
void AddLinkObjects(std::vector<cmLinkItem> const& objs);
- cmLinkItem ResolveLinkItem(int depender_index, const std::string& name);
+ cmLinkItem ResolveLinkItem(size_t depender_index, const std::string& name);
// One entry for each unique item.
std::vector<LinkEntry> EntryList;
- std::map<cmLinkItem, int> LinkEntryIndex;
+ std::map<cmLinkItem, size_t> LinkEntryIndex;
// map storing, for each group, the list of items
- std::map<int, std::vector<int>> GroupItems;
+ std::map<size_t, std::vector<size_t>> GroupItems;
// BFS of initial dependencies.
struct BFSEntry
{
- int Index;
- int GroupIndex;
+ size_t Index;
+ size_t GroupIndex;
const char* LibDepends;
};
std::queue<BFSEntry> BFSQueue;
@@ -126,18 +128,18 @@ private:
struct SharedDepEntry
{
cmLinkItem Item;
- int DependerIndex;
+ size_t DependerIndex;
};
std::queue<SharedDepEntry> SharedDepQueue;
- std::set<int> SharedDepFollowed;
- void FollowSharedDeps(int depender_index, cmLinkInterface const* iface,
+ std::set<size_t> SharedDepFollowed;
+ void FollowSharedDeps(size_t depender_index, cmLinkInterface const* iface,
bool follow_interface = false);
- void QueueSharedDependencies(int depender_index,
+ void QueueSharedDependencies(size_t 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 DependSet : public std::set<size_t>
{
};
struct DependSetList : public std::vector<DependSet>
@@ -162,41 +164,41 @@ private:
// Ordering algorithm.
void OrderLinkEntries();
std::vector<char> ComponentVisited;
- std::vector<int> ComponentOrder;
+ std::vector<size_t> ComponentOrder;
struct PendingComponent
{
// The real component id. Needed because the map is indexed by
// component topological index.
- int Id;
+ size_t 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;
+ size_t Count;
// The entries yet to be seen to complete the component.
- std::set<int> Entries;
+ std::set<size_t> Entries;
};
- std::map<int, PendingComponent> PendingComponents;
+ std::map<size_t, PendingComponent> PendingComponents;
std::unique_ptr<cmComputeComponentGraph> CCG;
- std::vector<int> FinalLinkOrder;
+ std::vector<size_t> FinalLinkOrder;
void DisplayComponents();
- void VisitComponent(unsigned int c);
- void VisitEntry(int index);
- PendingComponent& MakePendingComponent(unsigned int component);
- int ComputeComponentCount(NodeList const& nl);
+ void VisitComponent(size_t c);
+ void VisitEntry(size_t index);
+ PendingComponent& MakePendingComponent(size_t component);
+ size_t ComputeComponentCount(NodeList const& nl);
void DisplayFinalEntries();
// Record of the original link line.
- std::vector<int> OriginalEntries;
+ std::vector<size_t> OriginalEntries;
std::set<cmGeneratorTarget const*> OldWrongConfigItems;
void CheckWrongConfigItem(cmLinkItem const& item);
// Record of explicitly linked object files.
- std::vector<int> ObjectEntries;
+ std::vector<size_t> ObjectEntries;
- int ComponentOrderId;
+ size_t ComponentOrderId;
cmTargetLinkLibraryType LinkType;
bool HasConfig;
bool DebugMode;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 6cfdf62..ad8fb8b 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -30,7 +30,7 @@
#include "cmValue.h"
#include "cmake.h"
-//#define CM_COMPUTE_LINK_INFO_DEBUG
+// #define CM_COMPUTE_LINK_INFO_DEBUG
/*
Notes about linking on various platforms:
@@ -366,7 +366,7 @@ cmComputeLinkInformation::cmComputeLinkInformation(
this->LibraryFeatureDescriptors.emplace(
"__CMAKE_LINK_EXECUTABLE",
LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
- cmStrCat(this->LoaderFlag, "<LIBRARY>") });
+ cmStrCat(*this->LoaderFlag, "<LIBRARY>") });
}
// To link framework using a full path
this->LibraryFeatureDescriptors.emplace(
@@ -858,8 +858,8 @@ bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature)
return false;
}
- auto items =
- cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true);
+ auto items = cmExpandListWithBacktrace(*langFeature,
+ this->Target->GetBacktrace(), true);
if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
(items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
@@ -1016,8 +1016,8 @@ cmComputeLinkInformation::GetGroupFeature(std::string const& feature)
.first->second;
}
- auto items =
- cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true);
+ auto items = cmExpandListWithBacktrace(*langFeature,
+ this->Target->GetBacktrace(), true);
// replace LINKER: pattern
this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 3ff16a4..6763225 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -3,6 +3,7 @@
#include "cmComputeTargetDepends.h"
#include <cassert>
+#include <cstddef>
#include <cstdio>
#include <memory>
#include <sstream>
@@ -159,7 +160,7 @@ void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t,
// this point.
auto tii = this->TargetIndex.find(t);
assert(tii != this->TargetIndex.end());
- int i = tii->second;
+ size_t i = tii->second;
// Get its final dependencies.
EdgeList const& nl = this->FinalGraph[i];
@@ -178,7 +179,7 @@ void cmComputeTargetDepends::CollectTargets()
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());
+ size_t index = this->Targets.size();
this->TargetIndex[ti.get()] = index;
this->Targets.push_back(ti.get());
}
@@ -191,12 +192,12 @@ void cmComputeTargetDepends::CollectDepends()
this->InitialGraph.resize(this->Targets.size());
// Compute each dependency list.
- for (unsigned int i = 0; i < this->Targets.size(); ++i) {
+ for (size_t i = 0; i < this->Targets.size(); ++i) {
this->CollectTargetDepends(i);
}
}
-void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
+void cmComputeTargetDepends::CollectTargetDepends(size_t depender_index)
{
// Get the depender.
cmGeneratorTarget const* depender = this->Targets[depender_index];
@@ -261,7 +262,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
}
void cmComputeTargetDepends::AddInterfaceDepends(
- int depender_index, const cmGeneratorTarget* dependee,
+ size_t depender_index, const cmGeneratorTarget* dependee,
cmListFileBacktrace const& dependee_backtrace, const std::string& config,
std::set<cmLinkItem>& emitted)
{
@@ -290,7 +291,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(
}
void cmComputeTargetDepends::AddInterfaceDepends(
- int depender_index, cmLinkItem const& dependee_name,
+ size_t depender_index, cmLinkItem const& dependee_name,
const std::string& config, std::set<cmLinkItem>& emitted)
{
cmGeneratorTarget const* depender = this->Targets[depender_index];
@@ -312,7 +313,7 @@ void cmComputeTargetDepends::AddInterfaceDepends(
}
}
-void cmComputeTargetDepends::AddObjectDepends(int depender_index,
+void cmComputeTargetDepends::AddObjectDepends(size_t depender_index,
cmSourceFile const* o,
std::set<cmLinkItem>& emitted)
{
@@ -340,7 +341,7 @@ void cmComputeTargetDepends::AddObjectDepends(int depender_index,
}
}
-void cmComputeTargetDepends::AddTargetDepend(int depender_index,
+void cmComputeTargetDepends::AddTargetDepend(size_t depender_index,
cmLinkItem const& dependee_name,
bool linking, bool cross)
{
@@ -394,7 +395,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index,
}
void cmComputeTargetDepends::AddTargetDepend(
- int depender_index, cmGeneratorTarget const* dependee,
+ size_t depender_index, cmGeneratorTarget const* dependee,
cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross)
{
if (!dependee->IsInBuildSystem()) {
@@ -412,7 +413,7 @@ void cmComputeTargetDepends::AddTargetDepend(
// this point.
auto tii = this->TargetIndex.find(dependee);
assert(tii != this->TargetIndex.end());
- int dependee_index = tii->second;
+ size_t dependee_index = tii->second;
// Add this entry to the dependency graph.
this->InitialGraph[depender_index].emplace_back(dependee_index, !linking,
@@ -425,15 +426,15 @@ 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) {
+ size_t n = this->InitialGraph.size();
+ std::set<size_t> visited;
+ for (size_t i = 0; i < n; ++i) {
this->CollectSideEffectsForTarget(visited, i);
}
}
void cmComputeTargetDepends::CollectSideEffectsForTarget(
- std::set<int>& visited, int depender_index)
+ std::set<size_t>& visited, size_t depender_index)
{
if (!visited.count(depender_index)) {
auto& se = this->SideEffects[depender_index];
@@ -461,8 +462,8 @@ 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) {
+ size_t n = this->InitialGraph.size();
+ for (size_t i = 0; i < n; ++i) {
auto const& initialEdges = this->InitialGraph[i];
auto& intermediateEdges = this->IntermediateGraph[i];
cmGeneratorTarget const* gt = this->Targets[i];
@@ -488,7 +489,7 @@ void cmComputeTargetDepends::OptimizeLinkDependencies(
cmGeneratorTarget const* gt, cmGraphEdgeList& outputEdges,
cmGraphEdgeList const& inputEdges)
{
- std::set<int> emitted;
+ std::set<size_t> emitted;
for (auto const& edge : inputEdges) {
if (edge.IsStrong()) {
// Preserve strong edges
@@ -529,16 +530,16 @@ 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) {
+ size_t n = graph.size();
+ for (size_t 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,
+ fprintf(stderr, "target %zu is [%s]\n", depender_index,
depender->GetName().c_str());
for (cmGraphEdge const& ni : nl) {
- int dependee_index = ni;
+ size_t dependee_index = ni;
cmGeneratorTarget const* dependee = this->Targets[dependee_index];
- fprintf(stderr, " depends on target %d [%s] (%s)\n", dependee_index,
+ fprintf(stderr, " depends on target %zu [%s] (%s)\n", dependee_index,
dependee->GetName().c_str(), ni.IsStrong() ? "strong" : "weak");
}
}
@@ -548,16 +549,16 @@ void cmComputeTargetDepends::DisplayGraph(Graph const& graph,
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) {
+ size_t n = this->SideEffects.size();
+ for (size_t depender_index = 0; depender_index < n; ++depender_index) {
cmGeneratorTarget const* depender = this->Targets[depender_index];
- fprintf(stderr, "target %d is [%s]\n", depender_index,
+ fprintf(stderr, "target %zu 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],
+ fprintf(stderr, " from target %zu [%s]\n", this->TargetIndex[gt],
gt->GetName().c_str());
}
}
@@ -565,7 +566,7 @@ void cmComputeTargetDepends::DisplaySideEffects()
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],
+ fprintf(stderr, " from target %zu [%s]\n", this->TargetIndex[gt],
gt->GetName().c_str());
}
}
@@ -579,12 +580,12 @@ void cmComputeTargetDepends::DisplayComponents(
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) {
+ size_t n = components.size();
+ for (size_t 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,
+ fprintf(stderr, "Component (%zu):\n", c);
+ for (size_t i : nl) {
+ fprintf(stderr, " contains target %zu [%s]\n", i,
this->Targets[i]->GetName().c_str());
}
}
@@ -597,8 +598,8 @@ bool cmComputeTargetDepends::CheckComponents(
// 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) {
+ size_t nc = components.size();
+ for (size_t c = 0; c < nc; ++c) {
// Get the current component.
NodeList const& nl = components[c];
@@ -614,7 +615,7 @@ bool cmComputeTargetDepends::CheckComponents(
}
// Make sure the component is all STATIC_LIBRARY targets.
- for (int ni : nl) {
+ for (size_t ni : nl) {
if (this->Targets[ni]->GetType() != cmStateEnums::STATIC_LIBRARY) {
this->ComplainAboutBadComponent(ccg, c);
return false;
@@ -625,16 +626,16 @@ bool cmComputeTargetDepends::CheckComponents(
}
void cmComputeTargetDepends::ComplainAboutBadComponent(
- cmComputeComponentGraph const& ccg, int c, bool strong)
+ cmComputeComponentGraph const& ccg, size_t 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();
+ std::vector<size_t> const& cmap = ccg.GetComponentMap();
NodeList const& cl = components[c];
- for (int i : cl) {
+ for (size_t i : cl) {
// Get the depender.
cmGeneratorTarget const* depender = this->Targets[i];
@@ -645,7 +646,7 @@ void cmComputeTargetDepends::ComplainAboutBadComponent(
// List its dependencies that are inside the component.
EdgeList const& nl = this->InitialGraph[i];
for (cmGraphEdge const& ni : nl) {
- int j = ni;
+ size_t j = ni;
if (cmap[j] == c) {
cmGeneratorTarget const* dependee = this->Targets[j];
e << " depends on \"" << dependee->GetName() << "\""
@@ -669,10 +670,10 @@ void cmComputeTargetDepends::ComplainAboutBadComponent(
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)
+bool cmComputeTargetDepends::IntraComponent(std::vector<size_t> const& cmap,
+ size_t c, size_t i, size_t* head,
+ std::set<size_t>& emitted,
+ std::set<size_t>& visited)
{
if (!visited.insert(i).second) {
// Cycle in utility depends!
@@ -682,7 +683,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap,
// Honor strong intra-component edges in the final order.
EdgeList const& el = this->InitialGraph[i];
for (cmGraphEdge const& edge : el) {
- int j = edge;
+ size_t j = edge;
if (cmap[j] == c && edge.IsStrong()) {
this->FinalGraph[i].emplace_back(j, true, edge.IsCross(),
edge.GetBacktrace());
@@ -693,7 +694,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap,
}
// Prepend to a linear linked-list of intra-component edges.
- if (*head >= 0) {
+ if (*head != cmComputeComponentGraph::INVALID_COMPONENT) {
this->FinalGraph[i].emplace_back(*head, false, false,
cmListFileBacktrace());
} else {
@@ -716,16 +717,16 @@ bool cmComputeTargetDepends::ComputeFinalDepends(
this->FinalGraph.resize(this->InitialGraph.size());
// Choose intra-component edges to linearize dependencies.
- std::vector<int> const& cmap = ccg.GetComponentMap();
+ std::vector<size_t> 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;
+ size_t nc = components.size();
+ for (size_t c = 0; c < nc; ++c) {
+ size_t head = cmComputeComponentGraph::INVALID_COMPONENT;
+ std::set<size_t> emitted;
NodeList const& nl = components[c];
- for (int ni : cmReverseRange(nl)) {
- std::set<int> visited;
+ for (size_t ni : cmReverseRange(nl)) {
+ std::set<size_t> visited;
if (!this->IntraComponent(cmap, c, ni, &head, emitted, visited)) {
// Cycle in add_dependencies within component!
this->ComplainAboutBadComponent(ccg, c, true);
@@ -736,14 +737,14 @@ bool cmComputeTargetDepends::ComputeFinalDepends(
}
// 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;
+ size_t n = cgraph.size();
+ for (size_t depender_component = 0; depender_component < n;
++depender_component) {
- int depender_component_tail = this->ComponentTail[depender_component];
+ size_t 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];
+ size_t dependee_component = ni;
+ size_t dependee_component_head = this->ComponentHead[dependee_component];
this->FinalGraph[depender_component_tail].emplace_back(
dependee_component_head, ni.IsStrong(), ni.IsCross(),
ni.GetBacktrace());
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
index cdb66f8..3ed041b 100644
--- a/Source/cmComputeTargetDepends.h
+++ b/Source/cmComputeTargetDepends.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <cstddef>
#include <map>
#include <set>
#include <string>
@@ -51,28 +52,31 @@ private:
void CollectTargets();
void CollectDepends();
- void CollectTargetDepends(int depender_index);
- void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name,
+ void CollectTargetDepends(size_t depender_index);
+ void AddTargetDepend(size_t depender_index, cmLinkItem const& dependee_name,
bool linking, bool cross);
- void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee,
+ void AddTargetDepend(size_t 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 CollectSideEffectsForTarget(std::set<size_t>& visited,
+ size_t 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,
+ void AddInterfaceDepends(size_t depender_index,
+ cmLinkItem const& dependee_name,
const std::string& config,
std::set<cmLinkItem>& emitted);
- void AddInterfaceDepends(int depender_index,
+ void AddInterfaceDepends(size_t depender_index,
cmGeneratorTarget const* dependee,
cmListFileBacktrace const& dependee_backtrace,
const std::string& config,
std::set<cmLinkItem>& emitted);
- void AddObjectDepends(int depender_index, cmSourceFile const* o,
+ void AddObjectDepends(size_t depender_index, cmSourceFile const* o,
std::set<cmLinkItem>& emitted);
cmGlobalGenerator* GlobalGenerator;
bool DebugMode;
@@ -80,7 +84,7 @@ private:
// Collect all targets.
std::vector<cmGeneratorTarget const*> Targets;
- std::map<cmGeneratorTarget const*, int> TargetIndex;
+ std::map<cmGeneratorTarget const*, size_t> TargetIndex;
// Represent the target dependency graph. The entry at each
// top-level index corresponds to a depender whose dependencies are
@@ -99,11 +103,12 @@ private:
void DisplayComponents(cmComputeComponentGraph const& ccg,
const std::string& name);
bool CheckComponents(cmComputeComponentGraph const& ccg);
- void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c,
+ void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, size_t 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);
+ std::vector<size_t> ComponentHead;
+ std::vector<size_t> ComponentTail;
+ bool IntraComponent(std::vector<size_t> const& cmap, size_t c, size_t i,
+ size_t* head, std::set<size_t>& emitted,
+ std::set<size_t>& visited);
};
diff --git a/Source/cmConfigureLog.cxx b/Source/cmConfigureLog.cxx
new file mode 100644
index 0000000..a6658e2
--- /dev/null
+++ b/Source/cmConfigureLog.cxx
@@ -0,0 +1,303 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConfigureLog.h"
+
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+#include <sstream>
+#include <utility>
+
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
+#include <cm3p/json/writer.h>
+
+#include "cm_utf8.h"
+
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmConfigureLog::cmConfigureLog(std::string logDir,
+ std::vector<unsigned long> logVersions)
+ : LogDir(std::move(logDir))
+ , LogVersions(std::move(logVersions))
+{
+ // Always emit events for the latest log version.
+ static const unsigned long LatestLogVersion = 1;
+ if (!cm::contains(this->LogVersions, LatestLogVersion)) {
+ this->LogVersions.emplace_back(LatestLogVersion);
+ }
+
+ Json::StreamWriterBuilder builder;
+ this->Encoder.reset(builder.newStreamWriter());
+}
+
+cmConfigureLog::~cmConfigureLog()
+{
+ if (this->Opened) {
+ this->EndObject();
+ this->Stream << "...\n";
+ }
+}
+
+bool cmConfigureLog::IsAnyLogVersionEnabled(
+ std::vector<unsigned long> const& v) const
+{
+ // Both input lists are sorted. Look for a matching element.
+ auto i1 = v.cbegin();
+ auto i2 = this->LogVersions.cbegin();
+ while (i1 != v.cend() && i2 != this->LogVersions.cend()) {
+ if (*i1 < *i2) {
+ ++i1;
+ } else if (*i2 < *i1) {
+ ++i2;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+void cmConfigureLog::WriteBacktrace(cmMakefile const& mf)
+{
+ std::vector<std::string> backtrace;
+ auto root = mf.GetCMakeInstance()->GetHomeDirectory();
+ for (auto bt = mf.GetBacktrace(); !bt.Empty(); bt = bt.Pop()) {
+ auto t = bt.Top();
+ if (!t.Name.empty() || t.Line == cmListFileContext::DeferPlaceholderLine) {
+ t.FilePath = cmSystemTools::RelativeIfUnder(root, t.FilePath);
+ std::ostringstream s;
+ s << t;
+ backtrace.emplace_back(s.str());
+ }
+ }
+ this->WriteValue("backtrace"_s, backtrace);
+}
+
+void cmConfigureLog::WriteChecks(cmMakefile const& mf)
+{
+ if (!mf.GetCMakeInstance()->HasCheckInProgress()) {
+ return;
+ }
+ this->BeginObject("checks"_s);
+ for (auto const& value :
+ cmReverseRange(mf.GetCMakeInstance()->GetCheckInProgressMessages())) {
+ this->BeginLine() << "- ";
+ this->Encoder->write(value, &this->Stream);
+ this->EndLine();
+ }
+ this->EndObject();
+}
+
+void cmConfigureLog::EnsureInit()
+{
+ if (this->Opened) {
+ return;
+ }
+ assert(!this->Stream.is_open());
+
+ std::string name = cmStrCat(this->LogDir, "/CMakeConfigureLog.yaml");
+ this->Stream.open(name.c_str(), std::ios::out | std::ios::app);
+
+ this->Opened = true;
+
+ this->Stream << "\n---\n";
+ this->BeginObject("events"_s);
+}
+
+cmsys::ofstream& cmConfigureLog::BeginLine()
+{
+ for (unsigned i = 0; i < this->Indent; ++i) {
+ this->Stream << " ";
+ }
+ return this->Stream;
+}
+
+void cmConfigureLog::EndLine()
+{
+ this->Stream << std::endl;
+}
+
+void cmConfigureLog::BeginObject(cm::string_view key)
+{
+ this->BeginLine() << key << ':';
+ this->EndLine();
+ ++this->Indent;
+}
+
+void cmConfigureLog::EndObject()
+{
+ assert(this->Indent);
+ --this->Indent;
+}
+
+void cmConfigureLog::BeginEvent(std::string const& kind, cmMakefile const& mf)
+{
+ this->EnsureInit();
+
+ this->BeginLine() << '-';
+ this->EndLine();
+
+ ++this->Indent;
+
+ this->WriteValue("kind"_s, kind);
+ this->WriteBacktrace(mf);
+ this->WriteChecks(mf);
+}
+
+void cmConfigureLog::EndEvent()
+{
+ assert(this->Indent);
+ --this->Indent;
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, std::nullptr_t)
+{
+ this->BeginLine() << key << ": null";
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, bool value)
+{
+ this->BeginLine() << key << ": " << (value ? "true" : "false");
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, int value)
+{
+ this->BeginLine() << key << ": " << value;
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key, std::string const& value)
+{
+ this->BeginLine() << key << ": ";
+ this->Encoder->write(value, &this->Stream);
+ this->EndLine();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key,
+ std::vector<std::string> const& list)
+{
+ this->BeginObject(key);
+ for (auto const& value : list) {
+ this->BeginLine() << "- ";
+ this->Encoder->write(value, &this->Stream);
+ this->EndLine();
+ }
+ this->EndObject();
+}
+
+void cmConfigureLog::WriteValue(cm::string_view key,
+ std::map<std::string, std::string> const& map)
+{
+ static const std::string rawKeyChars = //
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" //
+ "abcdefghijklmnopqrstuvwxyz" //
+ "0123456789" //
+ "-_" //
+ ;
+ this->BeginObject(key);
+ for (auto const& entry : map) {
+ if (entry.first.find_first_not_of(rawKeyChars) == std::string::npos) {
+ this->WriteValue(entry.first, entry.second);
+ } else {
+ this->BeginLine();
+ this->Encoder->write(entry.first, &this->Stream);
+ this->Stream << ": ";
+ this->Encoder->write(entry.second, &this->Stream);
+ this->EndLine();
+ }
+ }
+ this->EndObject();
+}
+
+void cmConfigureLog::WriteLiteralTextBlock(cm::string_view key,
+ cm::string_view text)
+{
+ this->BeginLine() << key << ": |";
+ this->EndLine();
+
+ auto const l = text.length();
+ if (l) {
+ ++this->Indent;
+ this->BeginLine();
+
+ auto i = decltype(l){ 0 };
+ while (i < l) {
+ // YAML allows ' ', '\t' and "printable characters", but NOT other
+ // ASCII whitespace; those must be escaped, as must the upper UNICODE
+ // control characters (U+0080 - U+009F)
+ static constexpr unsigned int C1_LAST = 0x9F;
+ auto const c = static_cast<unsigned char>(text[i]);
+ switch (c) {
+ case '\r':
+ // Print a carriage return only if it is not followed by a line feed.
+ ++i;
+ if (i == l || text[i] != '\n') {
+ this->WriteEscape(c);
+ }
+ break;
+ case '\n':
+ // Print any line feeds except the very last one
+ if (i + 1 < l) {
+ this->EndLine();
+ this->BeginLine();
+ }
+ ++i;
+ break;
+ case '\t':
+ // Print horizontal tab verbatim
+ this->Stream.put('\t');
+ ++i;
+ break;
+ case '\\':
+ // Escape backslash for disambiguation
+ this->Stream << "\\\\";
+ ++i;
+ break;
+ default:
+ if (c >= 32 && c < 127) {
+ // Print ascii byte.
+ this->Stream.put(text[i]);
+ ++i;
+ break;
+ } else if (c > 127) {
+ // Decode a UTF-8 sequence.
+ unsigned int c32;
+ auto const* const s = text.data() + i;
+ auto const* const e = text.data() + l;
+ auto const* const n = cm_utf8_decode_character(s, e, &c32);
+ if (n > s && c32 > C1_LAST) {
+ auto const k = std::distance(s, n);
+ this->Stream.write(s, static_cast<std::streamsize>(k));
+ i += static_cast<unsigned>(k);
+ break;
+ }
+ }
+
+ // Escape non-printable byte.
+ this->WriteEscape(c);
+ ++i;
+ break;
+ }
+ }
+
+ this->EndLine();
+ --this->Indent;
+ }
+}
+
+void cmConfigureLog::WriteEscape(unsigned char c)
+{
+ char buffer[6];
+ int n = snprintf(buffer, sizeof(buffer), "\\x%02x", c);
+ if (n > 0) {
+ this->Stream.write(buffer, n);
+ }
+}
diff --git a/Source/cmConfigureLog.h b/Source/cmConfigureLog.h
new file mode 100644
index 0000000..7edc3ed
--- /dev/null
+++ b/Source/cmConfigureLog.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 <memory>
+#include <string>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmsys/FStream.hxx"
+
+namespace Json {
+class StreamWriter;
+}
+
+class cmMakefile;
+
+class cmConfigureLog
+{
+public:
+ /** Construct with the log directory and a sorted list of enabled log
+ versions. The latest log version will be enabled regardless. */
+ cmConfigureLog(std::string logDir, std::vector<unsigned long> logVersions);
+ ~cmConfigureLog();
+
+ /** Return true if at least one of the log versions in the given sorted
+ list is enabled. */
+ bool IsAnyLogVersionEnabled(std::vector<unsigned long> const& v) const;
+
+ void EnsureInit();
+
+ void BeginEvent(std::string const& kind, cmMakefile const& mf);
+ void EndEvent();
+
+ void BeginObject(cm::string_view key);
+ void EndObject();
+
+ // TODO other value types
+ void WriteValue(cm::string_view key, std::nullptr_t);
+ void WriteValue(cm::string_view key, bool value);
+ void WriteValue(cm::string_view key, int value);
+ void WriteValue(cm::string_view key, std::string const& value);
+ void WriteValue(cm::string_view key, std::vector<std::string> const& list);
+ void WriteValue(cm::string_view key,
+ std::map<std::string, std::string> const& map);
+
+ void WriteTextBlock(cm::string_view key, cm::string_view text);
+ void WriteLiteralTextBlock(cm::string_view key, cm::string_view text);
+
+ void WriteLiteralTextBlock(cm::string_view key, std::string const& text)
+ {
+ this->WriteLiteralTextBlock(key, cm::string_view{ text });
+ }
+
+private:
+ std::string LogDir;
+ std::vector<unsigned long> LogVersions;
+ cmsys::ofstream Stream;
+ unsigned Indent = 0;
+ bool Opened = false;
+
+ std::unique_ptr<Json::StreamWriter> Encoder;
+
+ void WriteBacktrace(cmMakefile const& mf);
+ void WriteChecks(cmMakefile const& mf);
+
+ cmsys::ofstream& BeginLine();
+ void EndLine();
+ void WriteEscape(unsigned char c);
+};
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index b44111d..acf1c20 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -7,6 +7,7 @@
#include <cstring>
#include <set>
#include <sstream>
+#include <type_traits>
#include <utility>
#include <cm/string_view>
@@ -16,6 +17,7 @@
#include "cmsys/FStream.hxx"
#include "cmArgumentParser.h"
+#include "cmConfigureLog.h"
#include "cmExportTryCompileFileGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -37,12 +39,14 @@ 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;
+/* clang-format off */
#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", "" }
+/* clang-format on */
// NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
SETUP_LANGUAGE(c_properties, C);
@@ -149,7 +153,9 @@ cmArgumentParser<Arguments> makeTryRunParser(
auto const TryCompileBaseArgParser =
cmArgumentParser<Arguments>{}
.Bind(0, &Arguments::CompileResultVariable)
+ .Bind("LOG_DESCRIPTION"_s, &Arguments::LogDescription)
.Bind("NO_CACHE"_s, &Arguments::NoCache)
+ .Bind("NO_LOG"_s, &Arguments::NoLog)
.Bind("CMAKE_FLAGS"_s, &Arguments::CMakeFlags)
.Bind("__CMAKE_INTERNAL"_s, &Arguments::CMakeInternal)
/* keep semicolon on own line */;
@@ -285,8 +291,8 @@ Arguments cmCoreTryCompile::ParseArgs(
return arguments;
}
-bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
- cmStateEnums::TargetType targetType)
+cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
+ Arguments& arguments, cmStateEnums::TargetType targetType)
{
this->OutputFile.clear();
// which signature were we called with ?
@@ -302,7 +308,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
arguments.SourceDirectoryOrFile->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"No <srcdir> specified.");
- return false;
+ return cm::nullopt;
}
sourceDirectory = *arguments.SourceDirectoryOrFile;
projectName = *arguments.ProjectName;
@@ -322,7 +328,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if (!arguments.BinaryDirectory || arguments.BinaryDirectory->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"No <bindir> specified.");
- return false;
+ return cm::nullopt;
}
if (*arguments.BinaryDirectory == unique_binary_directory) {
// leave empty until we're ready to create it, so we don't try to remove
@@ -335,7 +341,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
MessageType::FATAL_ERROR,
cmStrCat("<bindir> is not an absolute path:\n '",
*arguments.BinaryDirectory, "'"));
- return false;
+ return cm::nullopt;
}
this->BinaryDirectory = *arguments.BinaryDirectory;
// compute the binary dir when TRY_COMPILE is called with a src file
@@ -367,7 +373,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
"IMPORTED LINK_LIBRARIES. Got ",
tgt->GetName(), " of type ",
cmState::GetTargetTypeName(tgt->GetType()), "."));
- return false;
+ return cm::nullopt;
}
if (tgt->IsImported()) {
targets.emplace_back(i);
@@ -379,28 +385,28 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) {
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"COPY_FILE must be followed by a file path");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileError && arguments.CopyFileError->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR must be followed by a variable name");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileError && !arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE_ERROR may be used only with COPY_FILE");
- return false;
+ return cm::nullopt;
}
if (arguments.Sources && arguments.Sources->empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCES must be followed by at least one source file");
- return false;
+ return cm::nullopt;
}
if (this->SrcFileSignature) {
@@ -409,19 +415,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_CONTENT requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
if (arguments.SourceFromVar && arguments.SourceFromVar->size() % 2) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_VAR requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"SOURCE_FROM_FILE requires exactly two arguments");
- return false;
+ return cm::nullopt;
}
} else {
// only valid for srcfile signatures
@@ -430,19 +436,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
MessageType::FATAL_ERROR,
cmStrCat(arguments.LangProps.begin()->first,
" allowed only in source file signature"));
- return false;
+ return cm::nullopt;
}
if (!arguments.CompileDefs.empty()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COMPILE_DEFINITIONS allowed only in source file signature");
- return false;
+ return cm::nullopt;
}
if (arguments.CopyFileTo) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
"COPY_FILE allowed only in source file signature");
- return false;
+ return cm::nullopt;
}
}
@@ -462,9 +468,11 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
e << "Attempt at a recursive or nested TRY_COMPILE in directory\n"
<< " " << this->BinaryDirectory << "\n";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return false;
+ return cm::nullopt;
}
+ std::map<std::string, std::string> cmakeVariables;
+
std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt";
// which signature are we using? If we are using var srcfile bindir
if (this->SrcFileSignature) {
@@ -486,7 +494,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& content = (*arguments.SourceFromContent)[i + 1];
auto out = this->WriteSource(name, content, "SOURCE_FROM_CONTENT");
if (out.empty()) {
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(out));
}
@@ -499,7 +507,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& content = this->Makefile->GetDefinition(var);
auto out = this->WriteSource(name, content, "SOURCE_FROM_VAR");
if (out.empty()) {
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(out));
}
@@ -514,7 +522,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& msg =
cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\"");
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
- return false;
+ return cm::nullopt;
}
auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst);
@@ -523,7 +531,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src,
"\": ", result.GetString());
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg);
- return false;
+ return cm::nullopt;
}
sources.emplace_back(std::move(dstPath));
@@ -550,7 +558,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
err << cmJoin(langs, " ");
err << "\nSee project() command to enable other languages.";
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str());
- return false;
+ return cm::nullopt;
}
}
@@ -577,7 +585,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
<< cmSystemTools::GetLastSystemError();
/* clang-format on */
this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return false;
+ return cm::nullopt;
}
cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH");
@@ -586,6 +594,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
cmVersion::GetPatchVersion(), cmVersion::GetTweakVersion());
if (def) {
fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def->c_str());
+ cmakeVariables.emplace("CMAKE_MODULE_PATH", *def);
}
/* Set MSVC runtime library policy to match our selection. */
@@ -647,10 +656,12 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->GetDefinition(rulesOverrideLang)) {
fprintf(fout, "set(%s \"%s\")\n", rulesOverrideLang.c_str(),
rulesOverridePath->c_str());
+ cmakeVariables.emplace(rulesOverrideLang, *rulesOverridePath);
} else if (cmValue rulesOverridePath2 =
this->Makefile->GetDefinition(rulesOverrideBase)) {
fprintf(fout, "set(%s \"%s\")\n", rulesOverrideBase.c_str(),
rulesOverridePath2->c_str());
+ cmakeVariables.emplace(rulesOverrideBase, *rulesOverridePath2);
}
}
fprintf(fout, "project(CMAKE_TRY_COMPILE%s)\n", projectLangs.c_str());
@@ -681,6 +692,9 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
"set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
" ${COMPILE_DEFINITIONS}\")\n",
li.c_str(), li.c_str());
+ if (flags) {
+ cmakeVariables.emplace(langFlags, *flags);
+ }
}
switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0066)) {
case cmPolicies::WARN:
@@ -717,6 +731,9 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
cmValue flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
cmOutputConverter::EscapeForCMake(*flagsCfg).c_str());
+ if (flagsCfg) {
+ cmakeVariables.emplace(langFlagsCfg, *flagsCfg);
+ }
}
} break;
}
@@ -751,6 +768,9 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
cmOutputConverter::EscapeForCMake(*exeLinkFlags).c_str());
+ if (exeLinkFlags) {
+ cmakeVariables.emplace("CMAKE_EXE_LINKER_FLAGS", *exeLinkFlags);
+ }
}
break;
}
@@ -778,7 +798,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
"could not write export file.");
fclose(fout);
- return false;
+ return cm::nullopt;
}
fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n",
fname.c_str());
@@ -1038,12 +1058,14 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
vars.erase(kCMAKE_OSX_ARCHITECTURES);
std::string flag = "-DCMAKE_OSX_ARCHITECTURES=" + *tcArchs;
arguments.CMakeFlags.emplace_back(std::move(flag));
+ cmakeVariables.emplace("CMAKE_OSX_ARCHITECTURES", *tcArchs);
}
for (std::string const& var : vars) {
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + *val;
arguments.CMakeFlags.emplace_back(std::move(flag));
+ cmakeVariables.emplace(var, *val);
}
}
}
@@ -1054,6 +1076,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if (cmValue val = this->Makefile->GetDefinition(var)) {
std::string flag = "-D" + var + "=" + "'" + *val + "'";
arguments.CMakeFlags.emplace_back(std::move(flag));
+ cmakeVariables.emplace(var, *val);
}
}
}
@@ -1097,23 +1120,35 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
if ((res == 0) && arguments.CopyFileTo) {
std::string const& copyFile = *arguments.CopyFileTo;
- if (this->OutputFile.empty() ||
- !cmSystemTools::CopyFileAlways(this->OutputFile, copyFile)) {
- std::ostringstream emsg;
+ cmsys::SystemTools::CopyStatus status =
+ cmSystemTools::CopyFileAlways(this->OutputFile, copyFile);
+ if (!status) {
+ std::string err = status.GetString();
+ switch (status.Path) {
+ case cmsys::SystemTools::CopyStatus::SourcePath:
+ err = cmStrCat(err, " (input)");
+ break;
+ case cmsys::SystemTools::CopyStatus::DestPath:
+ err = cmStrCat(err, " (output)");
+ break;
+ default:
+ break;
+ }
/* clang-format off */
- emsg << "Cannot copy output executable\n"
- << " '" << this->OutputFile << "'\n"
- << "to destination specified by COPY_FILE:\n"
- << " '" << copyFile << "'\n";
+ err = cmStrCat(
+ "Cannot copy output executable\n",
+ " '", this->OutputFile, "'\n",
+ "to destination specified by COPY_FILE:\n",
+ " '", copyFile, "'\n",
+ "because:\n",
+ " ", err, "\n",
+ this->FindErrorMessage);
/* clang-format on */
- if (!this->FindErrorMessage.empty()) {
- emsg << this->FindErrorMessage;
- }
if (!arguments.CopyFileError) {
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str());
- return false;
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err);
+ return cm::nullopt;
}
- copyFileErrorMessage = emsg.str();
+ copyFileErrorMessage = std::move(err);
}
}
@@ -1122,7 +1157,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments,
this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
}
}
- return res == 0;
+
+ cmTryCompileResult result;
+ if (arguments.LogDescription) {
+ result.LogDescription = *arguments.LogDescription;
+ }
+ result.CMakeVariables = std::move(cmakeVariables);
+ result.SourceDirectory = sourceDirectory;
+ result.BinaryDirectory = this->BinaryDirectory;
+ result.Variable = *arguments.CompileResultVariable;
+ result.VariableCached = !arguments.NoCache;
+ result.Output = std::move(output);
+ result.ExitCode = res;
+ return cm::optional<cmTryCompileResult>(std::move(result));
}
bool cmCoreTryCompile::IsTemporary(std::string const& path)
@@ -1263,3 +1310,26 @@ std::string cmCoreTryCompile::WriteSource(std::string const& filename,
file.close();
return filepath;
}
+
+void cmCoreTryCompile::WriteTryCompileEventFields(
+ cmConfigureLog& log, cmTryCompileResult const& compileResult)
+{
+#ifndef CMAKE_BOOTSTRAP
+ if (compileResult.LogDescription) {
+ log.WriteValue("description"_s, *compileResult.LogDescription);
+ }
+ log.BeginObject("directories"_s);
+ log.WriteValue("source"_s, compileResult.SourceDirectory);
+ log.WriteValue("binary"_s, compileResult.BinaryDirectory);
+ log.EndObject();
+ if (!compileResult.CMakeVariables.empty()) {
+ log.WriteValue("cmakeVariables"_s, compileResult.CMakeVariables);
+ }
+ log.BeginObject("buildResult"_s);
+ log.WriteValue("variable"_s, compileResult.Variable);
+ log.WriteValue("cached"_s, compileResult.VariableCached);
+ log.WriteLiteralTextBlock("stdout"_s, compileResult.Output);
+ log.WriteValue("exitCode"_s, compileResult.ExitCode);
+ log.EndObject();
+#endif
+}
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 3e1e12c..ba38c19 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -14,10 +14,26 @@
#include "cmArgumentParserTypes.h"
#include "cmStateTypes.h"
+class cmConfigureLog;
class cmMakefile;
template <typename Iter>
class cmRange;
+struct cmTryCompileResult
+{
+ cm::optional<std::string> LogDescription;
+ std::map<std::string, std::string> CMakeVariables;
+
+ std::string SourceDirectory;
+ std::string BinaryDirectory;
+
+ bool VariableCached = true;
+ std::string Variable;
+
+ std::string Output;
+ int ExitCode = 1;
+};
+
/** \class cmCoreTryCompile
* \brief Base class for cmTryCompileCommand and cmTryRunCommand
*
@@ -58,7 +74,9 @@ public:
cm::optional<std::string> OutputVariable;
cm::optional<std::string> CopyFileTo;
cm::optional<std::string> CopyFileError;
+ cm::optional<ArgumentParser::NonEmpty<std::string>> LogDescription;
bool NoCache = false;
+ bool NoLog = false;
// Argument for try_run only.
// Keep in sync with warnings in cmCoreTryCompile::ParseArgs.
@@ -80,8 +98,8 @@ public:
* This function requires at least two \p arguments and will crash if given
* fewer.
*/
- bool TryCompileCode(Arguments& arguments,
- cmStateEnums::TargetType targetType);
+ cm::optional<cmTryCompileResult> TryCompileCode(
+ Arguments& arguments, cmStateEnums::TargetType targetType);
/**
* Returns \c true if \p path resides within a CMake temporary directory,
@@ -103,6 +121,9 @@ public:
*/
void FindOutputFile(const std::string& targetName);
+ static void WriteTryCompileEventFields(
+ cmConfigureLog& log, cmTryCompileResult const& compileResult);
+
std::string BinaryDirectory;
std::string OutputFile;
std::string FindErrorMessage;
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 41d4442..14c22e3 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -148,6 +148,14 @@ std::string EvaluateDepfile(std::string const& path,
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path);
return cge->Evaluate(lg, config);
}
+
+std::string EvaluateComment(const char* comment,
+ cmGeneratorExpression const& ge,
+ cmLocalGenerator* lg, std::string const& config)
+{
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(comment);
+ return cge->Evaluate(lg, config);
+}
}
cmCustomCommandGenerator::cmCustomCommandGenerator(
@@ -172,7 +180,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
};
}
- cmGeneratorExpression ge(cc.GetBacktrace());
+ cmGeneratorExpression ge(*lg->GetCMakeInstance(), cc.GetBacktrace());
cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse(
this->Target) };
@@ -417,7 +425,8 @@ std::string cmCustomCommandGenerator::GetDepfile() const
return "";
}
- cmGeneratorExpression ge(this->CC->GetBacktrace());
+ cmGeneratorExpression ge(*this->LG->GetCMakeInstance(),
+ this->CC->GetBacktrace());
return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig);
}
@@ -462,9 +471,19 @@ std::string cmCustomCommandGenerator::GetInternalDepfile() const
return this->ComputeInternalDepfile(this->OutputConfig, depfile);
}
-const char* cmCustomCommandGenerator::GetComment() const
+cm::optional<std::string> cmCustomCommandGenerator::GetComment() const
{
- return this->CC->GetComment();
+ const char* comment = this->CC->GetComment();
+ if (!comment) {
+ return cm::nullopt;
+ }
+ if (!*comment) {
+ return std::string();
+ }
+
+ cmGeneratorExpression ge(*this->LG->GetCMakeInstance(),
+ this->CC->GetBacktrace());
+ return EvaluateComment(comment, ge, this->LG, this->OutputConfig);
}
std::string cmCustomCommandGenerator::GetWorkingDirectory() const
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 73a8d38..4453654 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -58,7 +58,7 @@ public:
unsigned int GetNumberOfCommands() const;
std::string GetCommand(unsigned int c) const;
void AppendArguments(unsigned int c, std::string& cmd) const;
- const char* GetComment() const;
+ cm::optional<std::string> GetComment() const;
std::string GetWorkingDirectory() const;
std::vector<std::string> const& GetOutputs() const;
std::vector<std::string> const& GetByproducts() const;
diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx
index 84691c9..7952dfc 100644
--- a/Source/cmCxxModuleMapper.cxx
+++ b/Source/cmCxxModuleMapper.cxx
@@ -28,6 +28,38 @@ cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule(
namespace {
+std::string CxxModuleMapContentClang(CxxModuleLocations const& loc,
+ cmScanDepInfo const& obj)
+{
+ std::stringstream mm;
+
+ // Clang's command line only supports a single output. If more than one is
+ // expected, we cannot make a useful module map file.
+ if (obj.Provides.size() > 1) {
+ return {};
+ }
+
+ // A series of flags which tell the compiler where to look for modules.
+
+ for (auto const& p : obj.Provides) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+ // Force the TU to be considered a C++ module source file regardless of
+ // extension.
+ mm << "-x c++-module\n";
+
+ mm << "-fmodule-output=" << *bmi_loc << '\n';
+ break;
+ }
+ }
+ for (auto const& r : obj.Requires) {
+ if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
+ mm << "-fmodule-file=" << r.LogicalName << "=" << *bmi_loc << '\n';
+ }
+ }
+
+ return mm.str();
+}
+
std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
cmScanDepInfo const& obj)
{
@@ -179,6 +211,8 @@ cm::static_string_view CxxModuleMapExtension(
{
if (format) {
switch (*format) {
+ case CxxModuleMapFormat::Clang:
+ return ".pcm"_s;
case CxxModuleMapFormat::Gcc:
return ".gcm"_s;
case CxxModuleMapFormat::Msvc:
@@ -297,6 +331,8 @@ std::string CxxModuleMapContent(CxxModuleMapFormat format,
CxxModuleUsage const& usages)
{
switch (format) {
+ case CxxModuleMapFormat::Clang:
+ return CxxModuleMapContentClang(loc, obj);
case CxxModuleMapFormat::Gcc:
return CxxModuleMapContentGcc(loc, obj);
case CxxModuleMapFormat::Msvc:
diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h
index 8526a07..9271978 100644
--- a/Source/cmCxxModuleMapper.h
+++ b/Source/cmCxxModuleMapper.h
@@ -17,6 +17,7 @@
enum class CxxModuleMapFormat
{
+ Clang,
Gcc,
Msvc,
};
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index ac93c90..718097f 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -150,7 +150,9 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
std::ostream& internalDepends)
{
// Prepare the module search process.
- this->LocateModules();
+ if (!this->LocateModules()) {
+ return false;
+ }
// Get the directory in which stamp files will be stored.
const std::string& stamp_dir = this->TargetDirectory;
@@ -216,7 +218,7 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends,
return true;
}
-void cmDependsFortran::LocateModules()
+bool cmDependsFortran::LocateModules()
{
// Collect the set of modules provided and required by all sources.
using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap;
@@ -234,7 +236,7 @@ void cmDependsFortran::LocateModules()
// Short-circuit for simple targets.
if (this->Internal->TargetRequires.empty()) {
- return;
+ return true;
}
// Match modules provided by this target to those it requires.
@@ -243,15 +245,19 @@ void cmDependsFortran::LocateModules()
// Load information about other targets.
cmMakefile* mf = this->LocalGenerator->GetMakefile();
std::vector<std::string> infoFiles;
- mf->GetDefExpandList("CMAKE_TARGET_LINKED_INFO_FILES", infoFiles);
+ mf->GetDefExpandList("CMAKE_Fortran_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);
+ if (!fin) {
+ cmSystemTools::Error(cmStrCat("-E cmake_depends failed to open ", fname,
+ " for module information"));
+ return false;
}
+ this->MatchRemoteModules(fin, targetDir);
}
+ return true;
}
void cmDependsFortran::MatchLocalModules()
diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h
index a74db91..763f7bb 100644
--- a/Source/cmDependsFortran.h
+++ b/Source/cmDependsFortran.h
@@ -55,7 +55,7 @@ protected:
std::ostream& internalDepends) override;
// Find all the modules required by the target.
- void LocateModules();
+ bool LocateModules();
void MatchLocalModules();
void MatchRemoteModules(std::istream& fin, const std::string& stampDir);
void ConsiderModule(const std::string& name, const std::string& stampDir);
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
index d466a12..77c5295 100644
--- a/Source/cmDocumentation.cxx
+++ b/Source/cmDocumentation.cxx
@@ -16,7 +16,8 @@
#include "cmSystemTools.h"
#include "cmVersion.h"
-static const char* cmDocumentationStandardOptions[][2] = {
+namespace {
+const cmDocumentationEntry cmDocumentationStandardOptions[20] = {
{ "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
{ "--version,-version,/V [<file>]", "Print version number and exit." },
{ "--help-full [<file>]", "Print all help manuals and exit." },
@@ -42,22 +43,27 @@ static const char* cmDocumentationStandardOptions[][2] = {
{ "--help-variable var [<file>]", "Print help for one variable and exit." },
{ "--help-variable-list [<file>]",
"List variables with help available and exit." },
- { "--help-variables [<file>]", "Print cmake-variables manual and exit." },
- { nullptr, nullptr }
+ { "--help-variables [<file>]", "Print cmake-variables manual and exit." }
};
-static const char* cmDocumentationCPackGeneratorsHeader[][2] = {
- { nullptr, "The following generators are available on this platform:" },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationCPackGeneratorsHeader = {
+ {},
+ "The following generators are available on this platform:"
};
-static const char* cmDocumentationCMakeGeneratorsHeader[][2] = {
- { nullptr,
- "The following generators are available on this platform (* marks "
- "default):" },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationCMakeGeneratorsHeader = {
+ {},
+ "The following generators are available on this platform (* marks "
+ "default):"
};
+bool isOption(const char* arg)
+{
+ return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
+ (strcmp(arg, "/?") == 0));
+}
+} // anonymous namespace
+
cmDocumentation::cmDocumentation()
{
this->addCommonStandardDocSections();
@@ -148,14 +154,6 @@ bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os)
return result;
}
-#define GET_OPT_ARGUMENT(target) \
- do { \
- if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) { \
- (target) = argv[i + 1]; \
- i = i + 1; \
- }; \
- } while (false)
-
void cmDocumentation::WarnFormFromFilename(
cmDocumentation::RequestedHelpItem& request, bool& result)
{
@@ -217,6 +215,14 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
return true;
}
+ auto get_opt_argument = [=](const int nextIdx, std::string& target) -> bool {
+ if ((nextIdx < argc) && !isOption(argv[nextIdx])) {
+ target = argv[nextIdx];
+ return true;
+ }
+ return false;
+ };
+
// Search for supported help options.
bool result = false;
@@ -230,7 +236,7 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
(strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) ||
(strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) {
help.HelpType = cmDocumentation::Help;
- GET_OPT_ARGUMENT(help.Argument);
+ i += int(get_opt_argument(i + 1, help.Argument));
help.Argument = cmSystemTools::LowerCase(help.Argument);
// special case for single command
if (!help.Argument.empty()) {
@@ -239,25 +245,25 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
} else if (strcmp(argv[i], "--help-properties") == 0) {
help.HelpType = cmDocumentation::OneManual;
help.Argument = "cmake-properties.7";
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-policies") == 0) {
help.HelpType = cmDocumentation::OneManual;
help.Argument = "cmake-policies.7";
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-variables") == 0) {
help.HelpType = cmDocumentation::OneManual;
help.Argument = "cmake-variables.7";
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-modules") == 0) {
help.HelpType = cmDocumentation::OneManual;
help.Argument = "cmake-modules.7";
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-custom-modules") == 0) {
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
cmSystemTools::Message(
"Warning: --help-custom-modules no longer supported");
if (help.Filename.empty()) {
@@ -271,83 +277,79 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv,
} else if (strcmp(argv[i], "--help-commands") == 0) {
help.HelpType = cmDocumentation::OneManual;
help.Argument = "cmake-commands.7";
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-compatcommands") == 0) {
- GET_OPT_ARGUMENT(help.Filename);
cmSystemTools::Message(
"Warning: --help-compatcommands no longer supported");
return true;
} else if (strcmp(argv[i], "--help-full") == 0) {
help.HelpType = cmDocumentation::Full;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-html") == 0) {
- GET_OPT_ARGUMENT(help.Filename);
cmSystemTools::Message("Warning: --help-html no longer supported");
return true;
} else if (strcmp(argv[i], "--help-man") == 0) {
- GET_OPT_ARGUMENT(help.Filename);
cmSystemTools::Message("Warning: --help-man no longer supported");
return true;
} else if (strcmp(argv[i], "--help-command") == 0) {
help.HelpType = cmDocumentation::OneCommand;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
help.Argument = cmSystemTools::LowerCase(help.Argument);
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-module") == 0) {
help.HelpType = cmDocumentation::OneModule;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-property") == 0) {
help.HelpType = cmDocumentation::OneProperty;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-policy") == 0) {
help.HelpType = cmDocumentation::OnePolicy;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-variable") == 0) {
help.HelpType = cmDocumentation::OneVariable;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-manual") == 0) {
help.HelpType = cmDocumentation::OneManual;
- GET_OPT_ARGUMENT(help.Argument);
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Argument));
+ i += int(get_opt_argument(i + 1, help.Filename));
this->WarnFormFromFilename(help, result);
} else if (strcmp(argv[i], "--help-command-list") == 0) {
help.HelpType = cmDocumentation::ListCommands;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--help-module-list") == 0) {
help.HelpType = cmDocumentation::ListModules;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--help-property-list") == 0) {
help.HelpType = cmDocumentation::ListProperties;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--help-variable-list") == 0) {
help.HelpType = cmDocumentation::ListVariables;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--help-policy-list") == 0) {
help.HelpType = cmDocumentation::ListPolicies;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--help-manual-list") == 0) {
help.HelpType = cmDocumentation::ListManuals;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
} else if (strcmp(argv[i], "--copyright") == 0) {
- GET_OPT_ARGUMENT(help.Filename);
cmSystemTools::Message("Warning: --copyright no longer supported");
return true;
} else if ((strcmp(argv[i], "--version") == 0) ||
(strcmp(argv[i], "-version") == 0) ||
(strcmp(argv[i], "/V") == 0)) {
help.HelpType = cmDocumentation::Version;
- GET_OPT_ARGUMENT(help.Filename);
+ i += int(get_opt_argument(i + 1, help.Filename));
}
if (help.HelpType != None) {
// This is a help option. See if there is a file name given.
@@ -369,56 +371,12 @@ void cmDocumentation::SetSection(const char* name,
this->SectionAtName(name) = std::move(section);
}
-void cmDocumentation::SetSection(const char* name,
- std::vector<cmDocumentationEntry>& docs)
-{
- cmDocumentationSection sec{ name };
- sec.Append(docs);
- this->SetSection(name, std::move(sec));
-}
-
-void cmDocumentation::SetSection(const char* name, const char* docs[][2])
-{
- cmDocumentationSection sec{ name };
- sec.Append(docs);
- this->SetSection(name, std::move(sec));
-}
-
-void cmDocumentation::SetSections(
- std::map<std::string, cmDocumentationSection> sections)
-{
- for (auto& s : sections) {
- this->SetSection(s.first.c_str(), std::move(s.second));
- }
-}
cmDocumentationSection& cmDocumentation::SectionAtName(const char* name)
{
return this->AllSections.emplace(name, cmDocumentationSection{ name })
.first->second;
}
-void cmDocumentation::PrependSection(const char* name, const char* docs[][2])
-{
- this->SectionAtName(name).Prepend(docs);
-}
-
-void cmDocumentation::PrependSection(const char* name,
- std::vector<cmDocumentationEntry>& docs)
-{
- this->SectionAtName(name).Prepend(docs);
-}
-
-void cmDocumentation::AppendSection(const char* name, const char* docs[][2])
-{
- this->SectionAtName(name).Append(docs);
-}
-
-void cmDocumentation::AppendSection(const char* name,
- std::vector<cmDocumentationEntry>& docs)
-{
- this->SectionAtName(name).Append(docs);
-}
-
void cmDocumentation::AppendSection(const char* name,
cmDocumentationEntry& docs)
{
@@ -465,7 +423,7 @@ void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern)
}
std::sort(names.begin(), names.end());
for (std::string const& n : names) {
- os << n << "\n";
+ os << n << '\n';
}
}
@@ -501,7 +459,7 @@ bool cmDocumentation::PrintHelpOneManual(std::ostream& os)
// Argument was not a manual. Complain.
os << "Argument \"" << this->CurrentArgument
<< "\" to --help-manual is not an available manual. "
- << "Use --help-manual-list to see all available manuals.\n";
+ "Use --help-manual-list to see all available manuals.\n";
return false;
}
@@ -520,7 +478,7 @@ bool cmDocumentation::PrintHelpOneCommand(std::ostream& os)
// Argument was not a command. Complain.
os << "Argument \"" << this->CurrentArgument
<< "\" to --help-command is not a CMake command. "
- << "Use --help-command-list to see all commands.\n";
+ "Use --help-command-list to see all commands.\n";
return false;
}
@@ -553,7 +511,7 @@ bool cmDocumentation::PrintHelpListModules(std::ostream& os)
}
std::sort(modules.begin(), modules.end());
for (std::string const& m : modules) {
- os << m << "\n";
+ os << m << '\n';
}
return true;
}
@@ -567,7 +525,7 @@ bool cmDocumentation::PrintHelpOneProperty(std::ostream& os)
// Argument was not a property. Complain.
os << "Argument \"" << this->CurrentArgument
<< "\" to --help-property is not a CMake property. "
- << "Use --help-property-list to see all properties.\n";
+ "Use --help-property-list to see all properties.\n";
return false;
}
@@ -601,7 +559,6 @@ bool cmDocumentation::PrintHelpListGenerators(std::ostream& os)
{
const auto si = this->AllSections.find("Generators");
if (si != this->AllSections.end()) {
- this->Formatter.SetIndent(" ");
this->Formatter.PrintSection(os, si->second);
}
return true;
@@ -616,7 +573,7 @@ bool cmDocumentation::PrintHelpOneVariable(std::ostream& os)
// Argument was not a variable. Complain.
os << "Argument \"" << this->CurrentArgument
<< "\" to --help-variable is not a defined variable. "
- << "Use --help-variable-list to see all defined variables.\n";
+ "Use --help-variable-list to see all defined variables.\n";
return false;
}
@@ -662,12 +619,6 @@ const char* cmDocumentation::GetNameString() const
return "CMake";
}
-bool cmDocumentation::IsOption(const char* arg) const
-{
- return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) ||
- (strcmp(arg, "/?") == 0));
-}
-
bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
{
// CheckOptions abuses the Argument field to give us the file name.
@@ -691,7 +642,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
} else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) {
/* clang-format off */
os <<
- ".TH " << name << " " << ext[1] << " \"" <<
+ ".TH " << name << ' ' << ext[1] << " \"" <<
cmSystemTools::GetCurrentDateTime("%B %d, %Y") <<
"\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n"
".SH NAME\n"
@@ -704,7 +655,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os)
;
/* clang-format on */
} else {
- os << name << "\n\n" << summary << "\n" << detail;
+ os << name << "\n\n" << summary << '\n' << detail;
}
return true;
}
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
index 313be32..6930986 100644
--- a/Source/cmDocumentation.h
+++ b/Source/cmDocumentation.h
@@ -7,6 +7,7 @@
#include <iosfwd>
#include <map>
#include <string>
+#include <utility>
#include <vector>
#include "cmDocumentationFormatter.h"
@@ -15,9 +16,33 @@
struct cmDocumentationEntry;
/** Class to generate documentation. */
-class cmDocumentation : public cmDocumentationEnums
+class cmDocumentation
{
public:
+ /** Types of help provided. */
+ enum Type
+ {
+ None,
+ Version,
+ Usage,
+ Help,
+ Full,
+ ListManuals,
+ ListCommands,
+ ListModules,
+ ListProperties,
+ ListVariables,
+ ListPolicies,
+ ListGenerators,
+ OneManual,
+ OneCommand,
+ OneModule,
+ OneProperty,
+ OneVariable,
+ OnePolicy,
+ OldCustomModules
+ };
+
cmDocumentation();
/**
@@ -50,19 +75,26 @@ public:
/** Set a section of the documentation. Typical sections include Name,
Usage, Description, Options */
void SetSection(const char* sectionName, cmDocumentationSection section);
- void SetSection(const char* sectionName,
- std::vector<cmDocumentationEntry>& docs);
- void SetSection(const char* sectionName, const char* docs[][2]);
- void SetSections(std::map<std::string, cmDocumentationSection> sections);
+ template <typename Iterable>
+ void SetSection(const char* sectionName, const Iterable& docs)
+ {
+ cmDocumentationSection sec{ sectionName };
+ sec.Append(docs);
+ this->SetSection(sectionName, std::move(sec));
+ }
/** Add the documentation to the beginning/end of the section */
- void PrependSection(const char* sectionName, const char* docs[][2]);
- void PrependSection(const char* sectionName,
- std::vector<cmDocumentationEntry>& docs);
+ template <typename Iterable>
+ void PrependSection(const char* sectionName, const Iterable& docs)
+ {
+ this->SectionAtName(sectionName).Prepend(docs);
+ }
void PrependSection(const char* sectionName, cmDocumentationEntry& docs);
- void AppendSection(const char* sectionName, const char* docs[][2]);
- void AppendSection(const char* sectionName,
- std::vector<cmDocumentationEntry>& docs);
+ template <typename Iterable>
+ void AppendSection(const char* sectionName, const Iterable& docs)
+ {
+ this->SectionAtName(sectionName).Append(docs);
+ }
void AppendSection(const char* sectionName, cmDocumentationEntry& docs);
/** Add common (to all tools) documentation section(s) */
@@ -102,7 +134,6 @@ private:
bool PrintOldCustomModules(std::ostream& os);
const char* GetNameString() const;
- bool IsOption(const char* arg) const;
bool ShowGenerators;
@@ -114,7 +145,7 @@ private:
struct RequestedHelpItem
{
- cmDocumentationEnums::Type HelpType = None;
+ Type HelpType = None;
std::string Filename;
std::string Argument;
};
diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h
index 89a2899..d971836 100644
--- a/Source/cmDocumentationEntry.h
+++ b/Source/cmDocumentationEntry.h
@@ -9,26 +9,15 @@
/** Standard documentation entry for cmDocumentation's formatting. */
struct cmDocumentationEntry
{
- std::string Name;
- std::string Brief;
- char CustomNamePrefix = ' ';
- cmDocumentationEntry() = default;
- cmDocumentationEntry(const char* doc[2])
- {
- if (doc[0]) {
- this->Name = doc[0];
- }
- if (doc[1]) {
- this->Brief = doc[1];
- }
- }
- cmDocumentationEntry(const char* n, const char* b)
+#if __cplusplus <= 201103L
+ cmDocumentationEntry(const std::string& name, const std::string& brief)
+ : Name{ name }
+ , Brief{ brief }
{
- if (n) {
- this->Name = n;
- }
- if (b) {
- this->Brief = b;
- }
}
+#endif
+
+ std::string Name = {};
+ std::string Brief = {};
+ char CustomNamePrefix = ' ';
};
diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx
index 732637e..70ba1fc 100644
--- a/Source/cmDocumentationFormatter.cxx
+++ b/Source/cmDocumentationFormatter.cxx
@@ -2,7 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmDocumentationFormatter.h"
-#include <cstring>
+#include <algorithm>
+#include <cassert>
#include <iomanip>
#include <ostream>
#include <string>
@@ -11,178 +12,207 @@
#include "cmDocumentationEntry.h"
#include "cmDocumentationSection.h"
-cmDocumentationFormatter::cmDocumentationFormatter() = default;
-
-cmDocumentationFormatter::~cmDocumentationFormatter() = default;
+namespace {
+const char* skipSpaces(const char* ptr)
+{
+ assert(ptr);
+ for (; *ptr == ' '; ++ptr) {
+ ;
+ }
+ return ptr;
+}
+const char* skipToSpace(const char* ptr)
+{
+ assert(ptr);
+ for (; *ptr && (*ptr != '\n') && (*ptr != ' '); ++ptr) {
+ ;
+ }
+ return ptr;
+}
+}
void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
- const char* text)
+ std::string const& text) const
{
- if (!text) {
+ if (text.empty()) {
return;
}
- const char* ptr = text;
- while (*ptr) {
- // Any ptrs starting in a space are treated as preformatted text.
- std::string preformatted;
- while (*ptr == ' ') {
- for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
- preformatted.append(1, ch);
- }
- if (*ptr) {
- ++ptr;
- preformatted.append(1, '\n');
- }
- }
- if (!preformatted.empty()) {
- this->PrintPreformatted(os, preformatted.c_str());
+
+ struct Buffer
+ {
+ // clang-format off
+ using PrinterFn = void (cmDocumentationFormatter::*)(
+ std::ostream&, std::string const&
+ ) const;
+ // clang-format on
+ std::string collected;
+ const PrinterFn printer;
+ };
+ // const auto NORMAL_IDX = 0u;
+ const auto PREFORMATTED_IDX = 1u;
+ const auto HANDLERS_SIZE = 2u;
+ Buffer buffers[HANDLERS_SIZE] = {
+ { {}, &cmDocumentationFormatter::PrintParagraph },
+ { {}, &cmDocumentationFormatter::PrintPreformatted }
+ };
+
+ const auto padding = std::string(this->TextIndent, ' ');
+
+ for (std::size_t pos = 0u, eol = 0u; pos < text.size(); pos = eol) {
+ const auto current_idx = std::size_t(text[pos] == ' ');
+ // size_t(!bool(current_idx))
+ const auto other_idx = current_idx ^ 1u;
+
+ // Flush the other buffer if anything has been collected
+ if (!buffers[other_idx].collected.empty()) {
+ // NOTE Whatever the other index is, the current buffered
+ // string expected to be empty.
+ assert(buffers[current_idx].collected.empty());
+
+ (this->*buffers[other_idx].printer)(os, buffers[other_idx].collected);
+ buffers[other_idx].collected.clear();
}
- // Other ptrs are treated as paragraphs.
- std::string paragraph;
- for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
- paragraph.append(1, ch);
+ // ATTENTION The previous implementation had called `PrintParagraph()`
+ // **for every processed (char by char) input line**.
+ // The method unconditionally append the `\n' character after the
+ // printed text. To keep the backward-compatible behavior it's needed to
+ // add the '\n' character to the previously collected line...
+ if (!buffers[current_idx].collected.empty() &&
+ current_idx != PREFORMATTED_IDX) {
+ buffers[current_idx].collected += '\n';
}
- if (*ptr) {
- ++ptr;
- paragraph.append(1, '\n');
+
+ // Lookup EOL
+ eol = text.find('\n', pos);
+ if (current_idx == PREFORMATTED_IDX) {
+ buffers[current_idx].collected.append(padding);
}
- if (!paragraph.empty()) {
- this->PrintParagraph(os, paragraph.c_str());
+ buffers[current_idx].collected.append(
+ text, pos, eol == std::string::npos ? eol : ++eol - pos);
+ }
+
+ for (auto& buf : buffers) {
+ if (!buf.collected.empty()) {
+ (this->*buf.printer)(os, buf.collected);
}
}
}
void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
- const char* text)
+ std::string const& text) const
{
- bool newline = true;
- for (const char* ptr = text; *ptr; ++ptr) {
- if (newline && *ptr != '\n') {
- os << this->TextIndent;
- newline = false;
- }
- os << *ptr;
- if (*ptr == '\n') {
- newline = true;
- }
- }
- os << "\n";
+ os << text << '\n';
}
void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
- const char* text)
+ std::string const& text) const
{
- os << this->TextIndent;
+ if (this->TextIndent) {
+ os << std::string(this->TextIndent, ' ');
+ }
this->PrintColumn(os, text);
- os << "\n";
-}
-
-void cmDocumentationFormatter::SetIndent(const char* indent)
-{
- this->TextIndent = indent;
+ os << '\n';
}
-void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text)
+void cmDocumentationFormatter::PrintColumn(std::ostream& os,
+ std::string const& text) const
{
// Print text arranged in an indented column of fixed width.
- const char* l = text;
- long column = 0;
bool newSentence = false;
bool firstLine = true;
- int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
- // Loop until the end of the text.
- while (*l) {
- // Parse the next word.
- const char* r = l;
- while (*r && (*r != '\n') && (*r != ' ')) {
- ++r;
- }
+ assert(this->TextIndent < this->TextWidth);
+ const std::ptrdiff_t width = this->TextWidth - this->TextIndent;
+ std::ptrdiff_t column = 0;
+ // Loop until the end of the text.
+ for (const char *l = text.c_str(), *r = skipToSpace(text.c_str()); *l;
+ l = skipSpaces(r), r = skipToSpace(l)) {
// Does it fit on this line?
- if (r - l < (width - column - (newSentence ? 1 : 0))) {
+ if (r - l < width - column - std::ptrdiff_t(newSentence)) {
// Word fits on this line.
if (r > l) {
if (column) {
// Not first word on line. Separate from the previous word
// by a space, or two if this is a new sentence.
- if (newSentence) {
- os << " ";
- column += 2;
- } else {
- os << " ";
- column += 1;
- }
- } else {
+ os << &(" "[std::size_t(!newSentence)]);
+ column += 1u + std::ptrdiff_t(newSentence);
+ } else if (!firstLine && this->TextIndent) {
// First word on line. Print indentation unless this is the
// first line.
- os << (firstLine ? "" : this->TextIndent);
+ os << std::string(this->TextIndent, ' ');
}
// Print the word.
- os.write(l, static_cast<long>(r - l));
+ os.write(l, r - l);
newSentence = (*(r - 1) == '.');
}
if (*r == '\n') {
// Text provided a newline. Start a new line.
- os << "\n";
+ os << '\n';
++r;
column = 0;
firstLine = false;
} else {
// No provided newline. Continue this line.
- column += static_cast<long>(r - l);
+ column += r - l;
}
} else {
// Word does not fit on this line. Start a new line.
- os << "\n";
+ os << '\n';
firstLine = false;
if (r > l) {
- os << this->TextIndent;
- os.write(l, static_cast<long>(r - l));
- column = static_cast<long>(r - l);
+ os << std::string(this->TextIndent, ' ');
+ os.write(l, r - l);
+ column = r - l;
newSentence = (*(r - 1) == '.');
} else {
column = 0;
}
}
-
// Move to beginning of next word. Skip over whitespace.
- l = r;
- while (*l == ' ') {
- ++l;
- }
}
}
void cmDocumentationFormatter::PrintSection(
std::ostream& os, cmDocumentationSection const& section)
{
- os << section.GetName() << "\n";
+ const std::size_t PREFIX_SIZE =
+ sizeof(cmDocumentationEntry::CustomNamePrefix) + 1u;
+ // length of the "= " literal (see below)
+ const std::size_t SUFFIX_SIZE = 2u;
+ // legacy magic number ;-)
+ const std::size_t NAME_SIZE = 29u;
+
+ const std::size_t PADDING_SIZE = PREFIX_SIZE + SUFFIX_SIZE;
+ const std::size_t TITLE_SIZE = NAME_SIZE + PADDING_SIZE;
+
+ const auto savedIndent = this->TextIndent;
- const std::vector<cmDocumentationEntry>& entries = section.GetEntries();
- for (cmDocumentationEntry const& entry : entries) {
+ os << section.GetName() << '\n';
+
+ for (cmDocumentationEntry const& entry : section.GetEntries()) {
if (!entry.Name.empty()) {
- os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name;
- this->TextIndent = " ";
- int align = static_cast<int>(strlen(this->TextIndent)) - 4;
- for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) {
- os << " ";
- }
- if (entry.Name.size() > strlen(this->TextIndent) - 4) {
- os << "\n";
- os.write(this->TextIndent, strlen(this->TextIndent) - 2);
+ this->TextIndent = TITLE_SIZE;
+ os << std::setw(PREFIX_SIZE) << std::left << entry.CustomNamePrefix
+ << std::setw(int(std::max(NAME_SIZE, entry.Name.size())))
+ << entry.Name;
+ if (entry.Name.size() > NAME_SIZE) {
+ os << '\n' << std::setw(int(this->TextIndent - PREFIX_SIZE)) << ' ';
}
os << "= ";
- this->PrintColumn(os, entry.Brief.c_str());
- os << "\n";
+ this->PrintColumn(os, entry.Brief);
+ os << '\n';
} else {
- os << "\n";
- this->TextIndent = "";
- this->PrintFormatted(os, entry.Brief.c_str());
+ os << '\n';
+ this->TextIndent = 0u;
+ this->PrintFormatted(os, entry.Brief);
}
}
- os << "\n";
+
+ os << '\n';
+
+ this->TextIndent = savedIndent;
}
diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h
index cb3038a..e269f6a 100644
--- a/Source/cmDocumentationFormatter.h
+++ b/Source/cmDocumentationFormatter.h
@@ -5,40 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
-
-/** This is just a helper class to make it build with MSVC 6.0.
-Actually the enums and internal classes could directly go into
-cmDocumentation, but then MSVC6 complains in RequestedHelpItem that
-cmDocumentation is an undefined type and so it doesn't know the enums.
-Moving the enums to a class which is then already completely parsed helps
-against this. */
-class cmDocumentationEnums
-{
-public:
- /** Types of help provided. */
- enum Type
- {
- None,
- Version,
- Usage,
- Help,
- Full,
- ListManuals,
- ListCommands,
- ListModules,
- ListProperties,
- ListVariables,
- ListPolicies,
- ListGenerators,
- OneManual,
- OneCommand,
- OneModule,
- OneProperty,
- OneVariable,
- OnePolicy,
- OldCustomModules
- };
-};
+#include <string>
class cmDocumentationSection;
@@ -46,18 +13,15 @@ class cmDocumentationSection;
class cmDocumentationFormatter
{
public:
- cmDocumentationFormatter();
- virtual ~cmDocumentationFormatter();
- void PrintFormatted(std::ostream& os, const char* text);
-
- virtual void PrintSection(std::ostream& os,
- cmDocumentationSection const& section);
- virtual void PrintPreformatted(std::ostream& os, const char* text);
- virtual void PrintParagraph(std::ostream& os, const char* text);
- void PrintColumn(std::ostream& os, const char* text);
- void SetIndent(const char* indent);
+ void SetIndent(std::size_t indent) { this->TextIndent = indent; }
+ void PrintFormatted(std::ostream& os, std::string const& text) const;
+ void PrintSection(std::ostream& os, cmDocumentationSection const& section);
private:
- int TextWidth = 77;
- const char* TextIndent = "";
+ void PrintPreformatted(std::ostream& os, std::string const&) const;
+ void PrintParagraph(std::ostream& os, std::string const&) const;
+ void PrintColumn(std::ostream& os, std::string const&) const;
+
+ std::size_t TextWidth = 77u;
+ std::size_t TextIndent = 0u;
};
diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx
deleted file mode 100644
index 439da1b..0000000
--- a/Source/cmDocumentationSection.cxx
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmDocumentationSection.h"
-
-void cmDocumentationSection::Append(const char* data[][2])
-{
- int i = 0;
- while (data[i][1]) {
- this->Entries.emplace_back(data[i][0], data[i][1]);
- data += 1;
- }
-}
-
-void cmDocumentationSection::Prepend(const char* data[][2])
-{
- std::vector<cmDocumentationEntry> tmp;
- int i = 0;
- while (data[i][1]) {
- tmp.emplace_back(data[i][0], data[i][1]);
- data += 1;
- }
- this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end());
-}
-
-void cmDocumentationSection::Append(const char* n, const char* b)
-{
- this->Entries.emplace_back(n, b);
-}
diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h
index 276e520..b5e24fe 100644
--- a/Source/cmDocumentationSection.h
+++ b/Source/cmDocumentationSection.h
@@ -4,11 +4,10 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <iterator>
#include <string>
#include <vector>
-#include <cmext/algorithm>
-
#include "cmDocumentationEntry.h"
// Low-level interface for custom documents:
@@ -45,21 +44,20 @@ public:
{
this->Entries.push_back(entry);
}
- void Append(const std::vector<cmDocumentationEntry>& entries)
+
+ template <typename Iterable>
+ void Append(const Iterable& entries)
{
- cm::append(this->Entries, entries);
+ this->Entries.insert(std::end(this->Entries), std::begin(entries),
+ std::end(entries));
}
- /** Append an entry to this section using NULL terminated chars */
- void Append(const char* [][2]);
- void Append(const char* n, const char* b);
-
/** prepend some documentation to this section */
- void Prepend(const char* [][2]);
- void Prepend(const std::vector<cmDocumentationEntry>& entries)
+ template <typename Iterable>
+ void Prepend(const Iterable& entries)
{
- this->Entries.insert(this->Entries.begin(), entries.begin(),
- entries.end());
+ this->Entries.insert(std::begin(this->Entries), std::begin(entries),
+ std::end(entries));
}
private:
diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx
new file mode 100644
index 0000000..2827659
--- /dev/null
+++ b/Source/cmDyndepCollation.cxx
@@ -0,0 +1,652 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmDyndepCollation.h"
+
+#include <algorithm>
+#include <map>
+#include <ostream>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h" // IWYU pragma: keep
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallCxxModuleBmiGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmScanDepFormat.h"
+#include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+namespace {
+
+Json::Value CollationInformationCxxModules(
+ cmGeneratorTarget const* gt, std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb)
+{
+ cmTarget const* tgt = gt->Target;
+ auto all_file_sets = tgt->GetAllFileSetNames();
+ Json::Value tdi_cxx_module_info = Json::objectValue;
+ for (auto const& file_set_name : all_file_sets) {
+ auto const* file_set = tgt->GetFileSet(file_set_name);
+ if (!file_set) {
+ gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"",
+ file_set_name,
+ "\", but it was not found."));
+ continue;
+ }
+ auto fs_type = file_set->GetType();
+ // We only care about C++ module sources here.
+ if (fs_type != "CXX_MODULES"_s) {
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, gt->LocalGenerator, config, gt);
+ std::map<std::string, std::vector<std::string>> files_per_dirs;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
+ gt->LocalGenerator, config, gt);
+ }
+
+ std::map<std::string, cmSourceFile const*> sf_map;
+ {
+ std::vector<cmSourceFile const*> objectSources;
+ gt->GetObjectSources(objectSources, config);
+ for (auto const* sf : objectSources) {
+ auto full_path = sf->GetFullPath();
+ if (full_path.empty()) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" has a full path-less source file."));
+ continue;
+ }
+ sf_map[full_path] = sf;
+ }
+ }
+
+ Json::Value fs_dest = Json::nullValue;
+ for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
+ if (auto const* fsg =
+ dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
+ if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) {
+ fs_dest = fsg->GetDestination(config);
+ continue;
+ }
+ }
+ }
+
+ for (auto const& files_per_dir : files_per_dirs) {
+ for (auto const& file : files_per_dir.second) {
+ auto lookup = sf_map.find(file);
+ if (lookup == sf_map.end()) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file,
+ R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
+ continue;
+ }
+
+ auto const* sf = lookup->second;
+
+ if (!sf) {
+ gt->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
+ file, "\" which has not been tracked properly."));
+ continue;
+ }
+
+ auto obj_path = cb.ObjectFilePath(sf, config);
+ Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
+ Json::objectValue;
+
+ tdi_module_info["source"] = file;
+ tdi_module_info["relative-directory"] = files_per_dir.first;
+ tdi_module_info["name"] = file_set->GetName();
+ tdi_module_info["type"] = file_set->GetType();
+ tdi_module_info["visibility"] =
+ std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
+ tdi_module_info["destination"] = fs_dest;
+ }
+ }
+ }
+
+ return tdi_cxx_module_info;
+}
+
+Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt,
+ std::string const& config)
+{
+ cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
+ for (auto const& ig : gt->Makefile->GetInstallGenerators()) {
+ if (auto const* bmig =
+ dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
+ if (bmig->GetTarget() == gt) {
+ bmi_gen = bmig;
+ continue;
+ }
+ }
+ }
+ if (bmi_gen) {
+ Json::Value tdi_bmi_info = Json::objectValue;
+
+ tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
+ tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
+ const char* msg_level = "";
+ switch (bmi_gen->GetMessageLevel()) {
+ case cmInstallGenerator::MessageDefault:
+ break;
+ case cmInstallGenerator::MessageAlways:
+ msg_level = "MESSAGE_ALWAYS";
+ break;
+ case cmInstallGenerator::MessageLazy:
+ msg_level = "MESSAGE_LAZY";
+ break;
+ case cmInstallGenerator::MessageNever:
+ msg_level = "MESSAGE_NEVER";
+ break;
+ }
+ tdi_bmi_info["message-level"] = msg_level;
+ tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
+
+ return tdi_bmi_info;
+ }
+ return Json::nullValue;
+}
+
+Json::Value CollationInformationExports(cmGeneratorTarget const* gt)
+{
+ Json::Value tdi_exports = Json::arrayValue;
+ std::string export_name = gt->GetExportName();
+
+ auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets();
+ for (auto const& exp : all_install_exports) {
+ // Ignore exports sets which are not for this target.
+ auto const& targets = exp.second.GetTargetExports();
+ auto tgt_export =
+ std::find_if(targets.begin(), targets.end(),
+ [gt](std::unique_ptr<cmTargetExport> const& te) {
+ return te->Target == gt;
+ });
+ if (tgt_export == targets.end()) {
+ continue;
+ }
+
+ auto const* installs = exp.second.GetInstallations();
+ for (auto const* install : *installs) {
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = install->GetNamespace();
+ auto const& dest = install->GetDestination();
+ auto const& cxxm_dir = install->GetCxxModuleDirectory();
+ auto const& export_prefix = install->GetTempDir();
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = true;
+
+ tdi_exports.append(tdi_export_info);
+ }
+ }
+
+ auto const& all_build_exports = gt->Makefile->GetExportBuildFileGenerators();
+ for (auto const& exp : all_build_exports) {
+ std::vector<std::string> targets;
+ exp->GetTargets(targets);
+
+ // Ignore exports sets which are not for this target.
+ auto const& name = gt->GetName();
+ bool has_current_target =
+ std::any_of(targets.begin(), targets.end(),
+ [name](std::string const& tname) { return tname == name; });
+ if (!has_current_target) {
+ continue;
+ }
+
+ Json::Value tdi_export_info = Json::objectValue;
+
+ auto const& ns = exp->GetNamespace();
+ auto const& main_fn = exp->GetMainExportFileName();
+ auto const& cxxm_dir = exp->GetCxxModuleDirectory();
+ auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
+ auto const& export_prefix =
+ cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
+
+ tdi_export_info["namespace"] = ns;
+ tdi_export_info["export-name"] = export_name;
+ tdi_export_info["destination"] = dest;
+ tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
+ tdi_export_info["export-prefix"] = export_prefix;
+ tdi_export_info["install"] = false;
+
+ tdi_exports.append(tdi_export_info);
+ }
+
+ return tdi_exports;
+}
+}
+
+void cmDyndepCollation::AddCollationInformation(
+ Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb)
+{
+ tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb);
+ tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config);
+ tdi["exports"] = CollationInformationExports(gt);
+ tdi["config"] = config;
+}
+
+struct CxxModuleFileSet
+{
+ std::string Name;
+ std::string RelativeDirectory;
+ std::string SourcePath;
+ std::string Type;
+ cmFileSetVisibility Visibility;
+ cm::optional<std::string> Destination;
+};
+
+struct CxxModuleBmiInstall
+{
+ std::string Component;
+ std::string Destination;
+ bool ExcludeFromAll;
+ bool Optional;
+ std::string Permissions;
+ std::string MessageLevel;
+ std::string ScriptLocation;
+};
+
+struct CxxModuleExport
+{
+ std::string Name;
+ std::string Destination;
+ std::string Prefix;
+ std::string CxxModuleInfoDir;
+ std::string Namespace;
+ bool Install;
+};
+
+struct cmCxxModuleExportInfo
+{
+ std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
+ cm::optional<CxxModuleBmiInstall> BmiInstallation;
+ std::vector<CxxModuleExport> Exports;
+ std::string Config;
+};
+
+void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const
+{
+ delete ei;
+}
+
+std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
+cmDyndepCollation::ParseExportInfo(Json::Value const& tdi)
+{
+ auto export_info =
+ std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>(
+ new cmCxxModuleExportInfo);
+
+ export_info->Config = tdi["config"].asString();
+ if (export_info->Config.empty()) {
+ export_info->Config = "noconfig";
+ }
+ Json::Value const& tdi_exports = tdi["exports"];
+ if (tdi_exports.isArray()) {
+ for (auto const& tdi_export : tdi_exports) {
+ CxxModuleExport exp;
+ exp.Install = tdi_export["install"].asBool();
+ exp.Name = tdi_export["export-name"].asString();
+ exp.Destination = tdi_export["destination"].asString();
+ exp.Prefix = tdi_export["export-prefix"].asString();
+ exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
+ exp.Namespace = tdi_export["namespace"].asString();
+
+ export_info->Exports.push_back(exp);
+ }
+ }
+ auto const& bmi_installation = tdi["bmi-installation"];
+ if (bmi_installation.isObject()) {
+ CxxModuleBmiInstall bmi_install;
+
+ bmi_install.Component = bmi_installation["component"].asString();
+ bmi_install.Destination = bmi_installation["destination"].asString();
+ bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
+ bmi_install.Optional = bmi_installation["optional"].asBool();
+ bmi_install.Permissions = bmi_installation["permissions"].asString();
+ bmi_install.MessageLevel = bmi_installation["message-level"].asString();
+ bmi_install.ScriptLocation =
+ bmi_installation["script-location"].asString();
+
+ export_info->BmiInstallation = bmi_install;
+ }
+ Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
+ if (tdi_cxx_modules.isObject()) {
+ for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
+ CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()];
+ auto const& tdi_cxx_module_info = *i;
+ fsi.Name = tdi_cxx_module_info["name"].asString();
+ fsi.RelativeDirectory =
+ tdi_cxx_module_info["relative-directory"].asString();
+ fsi.SourcePath = tdi_cxx_module_info["source"].asString();
+ fsi.Type = tdi_cxx_module_info["type"].asString();
+ fsi.Visibility = cmFileSetVisibilityFromName(
+ tdi_cxx_module_info["visibility"].asString(), nullptr);
+ auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
+ if (tdi_fs_dest.isString()) {
+ fsi.Destination = tdi_fs_dest.asString();
+ }
+ }
+ }
+
+ return export_info;
+}
+
+bool cmDyndepCollation::WriteDyndepMetadata(
+ std::string const& lang, std::vector<cmScanDepInfo> const& objects,
+ cmCxxModuleExportInfo const& export_info,
+ cmDyndepMetadataCallbacks const& cb)
+{
+ // Only C++ supports any of the file-set or BMI installation considered
+ // below.
+ if (lang != "CXX"_s) {
+ return true;
+ }
+
+ bool result = true;
+
+ // Prepare the export information blocks.
+ std::string const config_upper =
+ cmSystemTools::UpperCase(export_info.Config);
+ std::vector<
+ std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
+ exports;
+ for (auto const& exp : export_info.Exports) {
+ std::unique_ptr<cmGeneratedFileStream> properties;
+
+ std::string const export_dir =
+ cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
+ std::string const property_file_path = cmStrCat(
+ export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
+ properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
+
+ // Set up the preamble.
+ *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
+ << "\"\n"
+ << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
+
+ exports.emplace_back(std::move(properties), &exp);
+ }
+
+ std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
+ if (export_info.BmiInstallation) {
+ bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
+ export_info.BmiInstallation->ScriptLocation);
+ }
+
+ auto cmEscape = [](cm::string_view str) {
+ return cmOutputConverter::EscapeForCMake(
+ str, cmOutputConverter::WrapQuotes::NoWrap);
+ };
+ auto install_destination =
+ [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
+ if (cmSystemTools::FileIsFullPath(dest)) {
+ return std::make_pair(true, cmEscape(dest));
+ }
+ return std::make_pair(false,
+ cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
+ };
+
+ // public/private requirement tracking.
+ std::set<std::string> private_modules;
+ std::map<std::string, std::set<std::string>> public_source_requires;
+
+ for (cmScanDepInfo const& object : objects) {
+ // Convert to forward slashes.
+ auto output_path = object.PrimaryOutput;
+#ifdef _WIN32
+ cmSystemTools::ConvertToUnixSlashes(output_path);
+#endif
+ // Find the fileset for this object.
+ auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
+ bool const has_provides = !object.Provides.empty();
+ if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
+ // If it provides anything, it should have a `CXX_MODULES` or
+ // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
+ if (has_provides) {
+ // Take the first module provided to provide context.
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(cmStrCat(
+ "Output ", object.PrimaryOutput, " provides the `",
+ provides.LogicalName,
+ "` module but it is not found in a `FILE_SET` of type ", ok_types));
+ result = false;
+ }
+
+ // This object file does not provide anything, so nothing more needs to
+ // be done.
+ continue;
+ }
+
+ auto const& file_set = fileset_info_itr->second;
+
+ // Verify the fileset type for the object.
+ if (file_set.Type == "CXX_MODULES"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(
+ cmStrCat("Output ", object.PrimaryOutput,
+ " is of type `CXX_MODULES` but does not provide a module"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
+ if (!has_provides) {
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module"));
+ result = false;
+ continue;
+ }
+ auto const& provides = object.Provides[0];
+ if (provides.LogicalName.find(':') == std::string::npos) {
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath,
+ " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
+ "provide a module partition"));
+ result = false;
+ continue;
+ }
+ } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
+ // TODO.
+ } else {
+ if (has_provides) {
+ auto const& provides = object.Provides[0];
+ char const* ok_types = "`CXX_MODULES`";
+ if (provides.LogicalName.find(':') != std::string::npos) {
+ ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
+ "it is not `export`ed)";
+ }
+ cmSystemTools::Error(
+ cmStrCat("Source ", file_set.SourcePath, " provides the `",
+ provides.LogicalName, "` C++ module but is of type `",
+ file_set.Type, "` module but must be of type ", ok_types));
+ result = false;
+ }
+
+ // Not a C++ module; ignore.
+ continue;
+ }
+
+ if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
+ // Nothing needs to be conveyed about non-`PUBLIC` modules.
+ for (auto const& p : object.Provides) {
+ private_modules.insert(p.LogicalName);
+ }
+ continue;
+ }
+
+ // The module is public. Record what it directly requires.
+ {
+ auto& reqs = public_source_requires[file_set.SourcePath];
+ for (auto const& r : object.Requires) {
+ reqs.insert(r.LogicalName);
+ }
+ }
+
+ // Write out properties and install rules for any exports.
+ for (auto const& p : object.Provides) {
+ bool bmi_dest_is_abs = false;
+ std::string bmi_destination;
+ if (export_info.BmiInstallation) {
+ auto dest =
+ install_destination(export_info.BmiInstallation->Destination);
+ bmi_dest_is_abs = dest.first;
+ bmi_destination = cmStrCat(dest.second, '/');
+ }
+
+ std::string install_bmi_path;
+ std::string build_bmi_path;
+ auto m = cb.ModuleFile(p.LogicalName);
+ if (m) {
+ install_bmi_path = cmStrCat(
+ bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
+ build_bmi_path = cmEscape(*m);
+ }
+
+ for (auto const& exp : exports) {
+ std::string iface_source;
+ if (exp.second->Install && file_set.Destination) {
+ auto dest = install_destination(*file_set.Destination);
+ iface_source = cmStrCat(
+ dest.second, '/', cmEscape(file_set.RelativeDirectory),
+ cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
+ } else {
+ iface_source = cmEscape(file_set.SourcePath);
+ }
+
+ std::string bmi_path;
+ if (exp.second->Install && export_info.BmiInstallation) {
+ bmi_path = install_bmi_path;
+ } else if (!exp.second->Install) {
+ bmi_path = build_bmi_path;
+ }
+
+ if (iface_source.empty()) {
+ // No destination for the C++ module source; ignore this property
+ // value.
+ continue;
+ }
+
+ *exp.first << " \"" << cmEscape(p.LogicalName) << '='
+ << iface_source;
+ if (!bmi_path.empty()) {
+ *exp.first << ',' << bmi_path;
+ }
+ *exp.first << "\"\n";
+ }
+
+ if (bmi_install_script) {
+ auto const& bmi_install = *export_info.BmiInstallation;
+
+ *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
+ << cmEscape(bmi_install.Component) << '\"';
+ if (!bmi_install.ExcludeFromAll) {
+ *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
+ }
+ *bmi_install_script << ")\n";
+ *bmi_install_script << " file(INSTALL\n"
+ " DESTINATION \"";
+ if (!bmi_dest_is_abs) {
+ *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
+ }
+ *bmi_install_script << cmEscape(bmi_install.Destination)
+ << "\"\n"
+ " TYPE FILE\n";
+ if (bmi_install.Optional) {
+ *bmi_install_script << " OPTIONAL\n";
+ }
+ if (!bmi_install.MessageLevel.empty()) {
+ *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
+ }
+ if (!bmi_install.Permissions.empty()) {
+ *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
+ << "\n";
+ }
+ *bmi_install_script << " FILES \"" << *m << "\")\n";
+ if (bmi_dest_is_abs) {
+ *bmi_install_script
+ << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
+ " \""
+ << cmEscape(cmSystemTools::GetFilenameName(*m))
+ << "\")\n"
+ " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(WARNING\n"
+ " \"ABSOLUTE path INSTALL DESTINATION : "
+ "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n"
+ " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
+ " message(FATAL_ERROR\n"
+ " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
+ "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
+ " endif ()\n";
+ }
+ *bmi_install_script << "endif ()\n";
+ }
+ }
+ }
+
+ // Add trailing parenthesis for the `set_property` call.
+ for (auto const& exp : exports) {
+ *exp.first << ")\n";
+ }
+
+ // Check that public sources only require public modules.
+ for (auto const& pub_reqs : public_source_requires) {
+ for (auto const& req : pub_reqs.second) {
+ if (private_modules.count(req)) {
+ cmSystemTools::Error(cmStrCat(
+ "Public C++ module source `", pub_reqs.first, "` requires the `",
+ req, "` C++ module which is provided by a private source"));
+ result = false;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h
new file mode 100644
index 0000000..e70ac09
--- /dev/null
+++ b/Source/cmDyndepCollation.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 <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+class cmGeneratorTarget;
+struct cmScanDepInfo;
+class cmSourceFile;
+
+namespace Json {
+class Value;
+}
+
+struct cmDyndepGeneratorCallbacks
+{
+ std::function<std::string(cmSourceFile const* sf, std::string const& config)>
+ ObjectFilePath;
+};
+
+struct cmDyndepMetadataCallbacks
+{
+ std::function<cm::optional<std::string>(std::string const& name)> ModuleFile;
+};
+
+struct cmCxxModuleExportInfo;
+struct cmCxxModuleExportInfoDeleter
+{
+ void operator()(cmCxxModuleExportInfo* ei) const;
+};
+
+struct cmDyndepCollation
+{
+ static void AddCollationInformation(Json::Value& tdi,
+ cmGeneratorTarget const* gt,
+ std::string const& config,
+ cmDyndepGeneratorCallbacks const& cb);
+
+ static std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>
+ ParseExportInfo(Json::Value const& tdi);
+ static bool WriteDyndepMetadata(std::string const& lang,
+ std::vector<cmScanDepInfo> const& objects,
+ cmCxxModuleExportInfo const& export_info,
+ cmDyndepMetadataCallbacks const& cb);
+};
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index 922b53f..c890e4b 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -27,7 +27,7 @@ struct FeatureData
bool Warned;
} LookupTable[] = {
// CxxModuleCMakeApi
- { "3c375311-a3c9-4396-a187-3227ef642046",
+ { "2182bf5c-ef0d-489a-91da-49dbc3090d2a",
"CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
"CMake's C++ module support is experimental. It is meant only for "
"experimentation and feedback to CMake developers.",
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 50bc78c..c8e2cb8 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -379,7 +379,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface(
const char* propName = "INTERFACE_INCLUDE_DIRECTORIES";
cmValue input = target->GetProperty(propName);
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());
std::string dirs = cmGeneratorExpression::Preprocess(
cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(te), ";"),
@@ -669,8 +669,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
while ((pos = input.find("$<TARGET_PROPERTY:", lastPos)) !=
std::string::npos) {
- std::string::size_type nameStartPos =
- pos + sizeof("$<TARGET_PROPERTY:") - 1;
+ std::string::size_type nameStartPos = pos + cmStrLen("$<TARGET_PROPERTY:");
std::string::size_type closePos = input.find('>', nameStartPos);
std::string::size_type commaPos = input.find(',', nameStartPos);
std::string::size_type nextOpenPos = input.find("$<", nameStartPos);
@@ -696,7 +695,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
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 nameStartPos = pos + cmStrLen("$<TARGET_NAME:");
std::string::size_type endPos = input.find('>', nameStartPos);
if (endPos == std::string::npos) {
errorString = "$<TARGET_NAME:...> expression incomplete";
@@ -721,7 +720,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression(
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 nameStartPos = pos + cmStrLen("$<LINK_ONLY:");
std::string::size_type endPos = input.find('>', nameStartPos);
if (endPos == std::string::npos) {
errorString = "$<LINK_ONLY:...> expression incomplete";
@@ -939,13 +938,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
// Isolate the file policy level.
// Support CMake versions as far back as 2.6 but also support using NEW
- // policy settings for up to CMake 3.23 (this upper limit may be reviewed
+ // policy settings for up to CMake 3.24 (this upper limit may be reviewed
// and increased from time to time). This reduces the opportunity for CMake
// warnings when an older export file is later used with newer CMake
// versions.
/* clang-format off */
os << "cmake_policy(PUSH)\n"
- << "cmake_policy(VERSION 2.8.3...3.23)\n";
+ << "cmake_policy(VERSION 2.8.3...3.24)\n";
/* clang-format on */
}
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 195737b..5e190f4 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -570,7 +570,7 @@ std::string cmExportInstallFileGenerator::GetFileSetDirectories(
auto configs =
gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
for (auto const& config : configs) {
@@ -617,7 +617,7 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles(
auto fileEntries = fileSet->CompileFileEntries();
auto directoryEntries = fileSet->CompileDirectoryEntries();
- cmGeneratorExpression destGe;
+ cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance());
auto destCge =
destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index e98aa05..33c057d 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -70,7 +70,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
return std::string();
}
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*tgt->Makefile->GetCMakeInstance());
std::unique_ptr<cmGeneratorExpressionDAGChecker> parentDagChecker;
if (propName == "INTERFACE_LINK_OPTIONS") {
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index ba4b326..a07acdc 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -67,7 +67,7 @@ cmExtraEclipseCDT4Generator::GetFactory()
if (factory.GetSupportedGlobalGenerators().empty()) {
// TODO: Verify if __CYGWIN__ should be checked.
-//#if defined(_WIN32) && !defined(__CYGWIN__)
+// #if defined(_WIN32) && !defined(__CYGWIN__)
#if defined(_WIN32)
factory.AddSupportedGlobalGenerator("NMake Makefiles");
factory.AddSupportedGlobalGenerator("MinGW Makefiles");
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 7f8374d..d1d3d25 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -18,6 +18,7 @@
#include "cmFileAPICMakeFiles.h"
#include "cmFileAPICache.h"
#include "cmFileAPICodemodel.h"
+#include "cmFileAPIConfigureLog.h"
#include "cmFileAPIToolchains.h"
#include "cmGlobalGenerator.h"
#include "cmStringAlgorithms.h"
@@ -66,6 +67,26 @@ void cmFileAPI::ReadQueries()
}
}
+std::vector<unsigned long> cmFileAPI::GetConfigureLogVersions()
+{
+ std::vector<unsigned long> versions;
+ auto getConfigureLogVersions = [&versions](Query const& q) {
+ for (Object const& o : q.Known) {
+ if (o.Kind == ObjectKind::ConfigureLog) {
+ versions.emplace_back(o.Version);
+ }
+ }
+ };
+ getConfigureLogVersions(this->TopQuery);
+ for (auto const& client : this->ClientQueries) {
+ getConfigureLogVersions(client.second.DirQuery);
+ }
+ std::sort(versions.begin(), versions.end());
+ versions.erase(std::unique(versions.begin(), versions.end()),
+ versions.end());
+ return versions;
+}
+
void cmFileAPI::WriteReplies()
{
if (this->QueryExists) {
@@ -241,6 +262,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
objects.push_back(o);
return true;
}
+ if (kindName == ObjectKindName(ObjectKind::ConfigureLog)) {
+ Object o;
+ o.Kind = ObjectKind::ConfigureLog;
+ if (verStr == "v1") {
+ o.Version = 1;
+ } else {
+ return false;
+ }
+ objects.push_back(o);
+ return true;
+ }
if (kindName == ObjectKindName(ObjectKind::Cache)) {
Object o;
o.Kind = ObjectKind::Cache;
@@ -411,11 +443,12 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
{
// Keep in sync with ObjectKind enum.
static const char* objectKindNames[] = {
- "codemodel", //
- "cache", //
- "cmakeFiles", //
- "toolchains", //
- "__test" //
+ "codemodel", //
+ "configureLog", //
+ "cache", //
+ "cmakeFiles", //
+ "toolchains", //
+ "__test" //
};
return objectKindNames[static_cast<size_t>(kind)];
}
@@ -442,6 +475,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
case ObjectKind::CodeModel:
value = this->BuildCodeModel(object);
break;
+ case ObjectKind::ConfigureLog:
+ value = this->BuildConfigureLog(object);
+ break;
case ObjectKind::Cache:
value = this->BuildCache(object);
break;
@@ -503,6 +539,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
if (kindName == this->ObjectKindName(ObjectKind::CodeModel)) {
r.Kind = ObjectKind::CodeModel;
+ } else if (kindName == this->ObjectKindName(ObjectKind::ConfigureLog)) {
+ r.Kind = ObjectKind::ConfigureLog;
} else if (kindName == this->ObjectKindName(ObjectKind::Cache)) {
r.Kind = ObjectKind::Cache;
} else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
@@ -530,6 +568,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
case ObjectKind::CodeModel:
this->BuildClientRequestCodeModel(r, versions);
break;
+ case ObjectKind::ConfigureLog:
+ this->BuildClientRequestConfigureLog(r, versions);
+ break;
case ObjectKind::Cache:
this->BuildClientRequestCache(r, versions);
break;
@@ -687,7 +728,7 @@ std::string cmFileAPI::NoSupportedVersion(
// The "codemodel" object kind.
// Update Help/manual/cmake-file-api.7.rst when updating this constant.
-static unsigned int const CodeModelV2Minor = 4;
+static unsigned int const CodeModelV2Minor = 5;
void cmFileAPI::BuildClientRequestCodeModel(
ClientRequest& r, std::vector<RequestVersion> const& versions)
@@ -719,6 +760,41 @@ Json::Value cmFileAPI::BuildCodeModel(Object const& object)
return codemodel;
}
+// The "configureLog" object kind.
+
+// Update Help/manual/cmake-file-api.7.rst when updating this constant.
+static unsigned int const ConfigureLogV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestConfigureLog(
+ 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 <= ConfigureLogV1Minor)) {
+ r.Version = v.Major;
+ break;
+ }
+ }
+ if (!r.Version) {
+ r.Error = NoSupportedVersion(versions);
+ }
+}
+
+Json::Value cmFileAPI::BuildConfigureLog(Object const& object)
+{
+ Json::Value configureLog = cmFileAPIConfigureLogDump(*this, object.Version);
+ configureLog["kind"] = this->ObjectKindName(object.Kind);
+
+ Json::Value& version = configureLog["version"];
+ if (object.Version == 1) {
+ version = BuildVersion(1, ConfigureLogV1Minor);
+ } else {
+ return configureLog; // should be unreachable
+ }
+
+ return configureLog;
+}
+
// The "cache" object kind.
static unsigned int const CacheV2Minor = 0;
@@ -870,6 +946,14 @@ Json::Value cmFileAPI::ReportCapabilities()
{
Json::Value request = Json::objectValue;
+ request["kind"] = ObjectKindName(ObjectKind::ConfigureLog);
+ Json::Value& versions = request["version"] = Json::arrayValue;
+ versions.append(BuildVersion(1, ConfigureLogV1Minor));
+ 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));
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 22302b4..6d7678f 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -24,6 +24,9 @@ public:
/** Read fileapi queries from disk. */
void ReadQueries();
+ /** Get the list of configureLog object kind versions requested. */
+ std::vector<unsigned long> GetConfigureLogVersions();
+
/** Write fileapi replies to disk. */
void WriteReplies();
@@ -54,6 +57,7 @@ private:
enum class ObjectKind
{
CodeModel,
+ ConfigureLog,
Cache,
CMakeFiles,
Toolchains,
@@ -193,6 +197,10 @@ private:
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildCodeModel(Object const& object);
+ void BuildClientRequestConfigureLog(
+ ClientRequest& r, std::vector<RequestVersion> const& versions);
+ Json::Value BuildConfigureLog(Object const& object);
+
void BuildClientRequestCache(ClientRequest& r,
std::vector<RequestVersion> const& versions);
Json::Value BuildCache(Object const& object);
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 0581802..d3683d4 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -17,6 +17,7 @@
#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include <cm3p/json/value.h>
@@ -44,6 +45,7 @@
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmSourceFile.h"
#include "cmSourceGroup.h"
#include "cmState.h"
@@ -434,6 +436,8 @@ class Target
std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap;
std::vector<CompileGroup> CompileGroups;
+ using FileSetDatabase = std::map<std::string, Json::ArrayIndex>;
+
template <typename T>
JBT<T> ToJBT(BT<T> const& bt)
{
@@ -444,6 +448,7 @@ class Target
JBTs<T> ToJBTs(BTs<T> const& bts)
{
std::vector<JBTIndex> ids;
+ ids.reserve(bts.Backtraces.size());
for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
ids.emplace_back(this->Backtraces.Add(backtrace));
}
@@ -466,9 +471,12 @@ class Target
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();
+ std::pair<Json::Value, FileSetDatabase> DumpFileSets();
+ Json::Value DumpFileSet(cmFileSet const* fs,
+ std::vector<std::string> const& directories);
+ Json::Value DumpSources(FileSetDatabase const& fsdb);
Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
- Json::ArrayIndex si);
+ Json::ArrayIndex si, FileSetDatabase const& fsdb);
Json::Value DumpSourceGroups();
Json::Value DumpSourceGroup(SourceGroup& sg);
Json::Value DumpCompileGroups();
@@ -1216,7 +1224,13 @@ Json::Value Target::Dump()
{
this->ProcessLanguages();
- target["sources"] = this->DumpSources();
+ auto fileSetInfo = this->DumpFileSets();
+
+ if (!fileSetInfo.first.isNull()) {
+ target["fileSets"] = fileSetInfo.first;
+ }
+
+ target["sources"] = this->DumpSources(fileSetInfo.second);
Json::Value folder = this->DumpFolder();
if (!folder.isNull()) {
@@ -1527,29 +1541,113 @@ Json::Value Target::DumpPaths()
return paths;
}
-Json::Value Target::DumpSources()
+std::pair<Json::Value, Target::FileSetDatabase> Target::DumpFileSets()
+{
+ Json::Value fsJson = Json::nullValue;
+ FileSetDatabase fsdb;
+
+ // Build the fileset database.
+ auto const* tgt = this->GT->Target;
+ auto const& fs_names = tgt->GetAllFileSetNames();
+
+ if (!fs_names.empty()) {
+ fsJson = Json::arrayValue;
+ size_t fsIndex = 0;
+ for (auto const& fs_name : fs_names) {
+ auto const* fs = tgt->GetFileSet(fs_name);
+ if (!fs) {
+ this->GT->Makefile->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", fs_name,
+ "\", but it was not found."));
+ continue;
+ }
+
+ auto fileEntries = fs->CompileFileEntries();
+ auto directoryEntries = fs->CompileDirectoryEntries();
+
+ auto directories = fs->EvaluateDirectoryEntries(
+ directoryEntries, this->GT->LocalGenerator, this->Config, this->GT);
+
+ fsJson.append(this->DumpFileSet(fs, directories));
+
+ std::map<std::string, std::vector<std::string>> files_per_dirs;
+ for (auto const& entry : fileEntries) {
+ fs->EvaluateFileEntry(directories, files_per_dirs, entry,
+ this->GT->LocalGenerator, this->Config,
+ this->GT);
+ }
+
+ for (auto const& files_per_dir : files_per_dirs) {
+ auto const& dir = files_per_dir.first;
+ for (auto const& file : files_per_dir.second) {
+ std::string sf_path;
+ if (dir.empty()) {
+ sf_path = file;
+ } else {
+ sf_path = cmStrCat(dir, '/', file);
+ }
+ fsdb[sf_path] = static_cast<Json::ArrayIndex>(fsIndex);
+ }
+ }
+
+ ++fsIndex;
+ }
+ }
+
+ return std::make_pair(fsJson, fsdb);
+}
+
+Json::Value Target::DumpFileSet(cmFileSet const* fs,
+ std::vector<std::string> const& directories)
+{
+ Json::Value fileSet = Json::objectValue;
+
+ fileSet["name"] = fs->GetName();
+ fileSet["type"] = fs->GetType();
+ fileSet["visibility"] =
+ std::string(cmFileSetVisibilityToName(fs->GetVisibility()));
+
+ Json::Value baseDirs = Json::arrayValue;
+ for (auto const& directory : directories) {
+ baseDirs.append(directory);
+ }
+ fileSet["baseDirectories"] = baseDirs;
+
+ return fileSet;
+}
+
+Json::Value Target::DumpSources(FileSetDatabase const& fsdb)
{
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()));
+ sources.append(this->DumpSource(sk, sources.size(), fsdb));
}
return sources;
}
Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
- Json::ArrayIndex si)
+ Json::ArrayIndex si,
+ FileSetDatabase const& fsdb)
{
Json::Value source = Json::objectValue;
- std::string const path = sk.Source.Value->ResolveFullPath();
+ cmSourceFile* sf = sk.Source.Value;
+ std::string const path = sf->ResolveFullPath();
source["path"] = RelativeIfUnder(this->TopSource, path);
if (sk.Source.Value->GetIsGenerated()) {
source["isGenerated"] = true;
}
this->AddBacktrace(source, sk.Source.Backtrace);
+ auto fsit = fsdb.find(path);
+ if (fsit != fsdb.end()) {
+ source["fileSetIndex"] = fsit->second;
+ }
+
if (cmSourceGroup* sg =
this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
diff --git a/Source/cmFileAPIConfigureLog.cxx b/Source/cmFileAPIConfigureLog.cxx
new file mode 100644
index 0000000..ad0997c
--- /dev/null
+++ b/Source/cmFileAPIConfigureLog.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 "cmFileAPIConfigureLog.h"
+
+#include <cm3p/json/value.h>
+
+#include "cmFileAPI.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+namespace {
+
+class ConfigureLog
+{
+ cmFileAPI& FileAPI;
+ unsigned long Version;
+
+ Json::Value DumpPath();
+ Json::Value DumpEventKindNames();
+
+public:
+ ConfigureLog(cmFileAPI& fileAPI, unsigned long version);
+ Json::Value Dump();
+};
+
+ConfigureLog::ConfigureLog(cmFileAPI& fileAPI, unsigned long version)
+ : FileAPI(fileAPI)
+ , Version(version)
+{
+ static_cast<void>(this->Version);
+}
+
+Json::Value ConfigureLog::Dump()
+{
+ Json::Value configureLog = Json::objectValue;
+ configureLog["path"] = this->DumpPath();
+ configureLog["eventKindNames"] = this->DumpEventKindNames();
+ return configureLog;
+}
+
+Json::Value ConfigureLog::DumpPath()
+{
+ return cmStrCat(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory(),
+ "/CMakeFiles/CMakeConfigureLog.yaml");
+}
+
+Json::Value ConfigureLog::DumpEventKindNames()
+{
+ // Report at most one version of each event kind.
+ // If a new event kind is added, increment ConfigureLogV1Minor.
+ // If a new version of an existing event kind is added, a new
+ // major version of the configureLog object kind is needed.
+ Json::Value eventKindNames = Json::arrayValue;
+ if (this->Version == 1) {
+ eventKindNames.append("message-v1"); // WriteMessageEvent
+ eventKindNames.append("try_compile-v1"); // WriteTryCompileEvent
+ eventKindNames.append("try_run-v1"); // WriteTryRunEvent
+ }
+ return eventKindNames;
+}
+}
+
+Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI,
+ unsigned long version)
+{
+ ConfigureLog configureLog(fileAPI, version);
+ return configureLog.Dump();
+}
diff --git a/Source/cmFileAPIConfigureLog.h b/Source/cmFileAPIConfigureLog.h
new file mode 100644
index 0000000..deaa403
--- /dev/null
+++ b/Source/cmFileAPIConfigureLog.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 cmFileAPIConfigureLogDump(cmFileAPI& fileAPI,
+ unsigned long version);
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index fe38db5..00a68a8 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -845,8 +845,10 @@ bool HandleMakeDirectoryCommand(std::vector<std::string> const& args,
cmSystemTools::SetFatalErrorOccurred();
return false;
}
- if (!cmSystemTools::MakeDirectory(*cdir)) {
- std::string error = "problem creating directory: " + *cdir;
+ cmsys::Status mkdirStatus = cmSystemTools::MakeDirectory(*cdir);
+ if (!mkdirStatus) {
+ std::string error = cmStrCat("failed to create directory:\n ", *cdir,
+ "\nbecause: ", mkdirStatus.GetString());
status.SetError(error);
return false;
}
@@ -1408,12 +1410,14 @@ bool HandleCopyFile(std::vector<std::string> const& args,
struct Arguments
{
+ bool InputMayBeRecent = false;
bool OnlyIfDifferent = false;
std::string Result;
};
static auto const parser =
cmArgumentParser<Arguments>{}
+ .Bind("INPUT_MAY_BE_RECENT"_s, &Arguments::InputMayBeRecent)
.Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent)
.Bind("RESULT"_s, &Arguments::Result);
@@ -1456,9 +1460,13 @@ bool HandleCopyFile(std::vector<std::string> const& args,
} else {
when = cmSystemTools::CopyWhen::Always;
}
+ cmSystemTools::CopyInputRecent const inputRecent = arguments.InputMayBeRecent
+ ? cmSystemTools::CopyInputRecent::Yes
+ : cmSystemTools::CopyInputRecent::No;
std::string err;
- if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) ==
+ if (cmSystemTools::CopySingleFile(oldname, newname, when, inputRecent,
+ &err) ==
cmSystemTools::CopyResult::Success) {
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, "0");
@@ -1621,6 +1629,14 @@ int cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr,
return 0;
}
+# if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM >= 0x072000
+const CURLoption CM_CURLOPT_XFERINFOFUNCTION = CURLOPT_XFERINFOFUNCTION;
+using cm_curl_off_t = curl_off_t;
+# else
+const CURLoption CM_CURLOPT_XFERINFOFUNCTION = CURLOPT_PROGRESSFUNCTION;
+using cm_curl_off_t = double;
+# endif
+
class cURLProgressHelper
{
public:
@@ -1630,12 +1646,14 @@ public:
{
}
- bool UpdatePercentage(double value, double total, std::string& status)
+ bool UpdatePercentage(cm_curl_off_t value, cm_curl_off_t total,
+ std::string& status)
{
long OldPercentage = this->CurrentPercentage;
- if (total > 0.0) {
- this->CurrentPercentage = std::lround(value / total * 100.0);
+ if (total > 0) {
+ this->CurrentPercentage = std::lround(
+ static_cast<double>(value) / static_cast<double>(total) * 100.0);
if (this->CurrentPercentage > 100) {
// Avoid extra progress reports for unexpected data beyond total.
this->CurrentPercentage = 100;
@@ -1660,8 +1678,9 @@ private:
std::string Text;
};
-int cmFileDownloadProgressCallback(void* clientp, double dltotal, double dlnow,
- double ultotal, double ulnow)
+int cmFileDownloadProgressCallback(void* clientp, cm_curl_off_t dltotal,
+ cm_curl_off_t dlnow, cm_curl_off_t ultotal,
+ cm_curl_off_t ulnow)
{
cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
@@ -1677,8 +1696,9 @@ int cmFileDownloadProgressCallback(void* clientp, double dltotal, double dlnow,
return 0;
}
-int cmFileUploadProgressCallback(void* clientp, double dltotal, double dlnow,
- double ultotal, double ulnow)
+int cmFileUploadProgressCallback(void* clientp, cm_curl_off_t dltotal,
+ cm_curl_off_t dlnow, cm_curl_off_t ultotal,
+ cm_curl_off_t ulnow)
{
cURLProgressHelper* helper = reinterpret_cast<cURLProgressHelper*>(clientp);
@@ -2054,7 +2074,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
check_curl_result(res, "DOWNLOAD cannot set noprogress value: ");
- res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ res = ::curl_easy_setopt(curl, CM_CURLOPT_XFERINFOFUNCTION,
cmFileDownloadProgressCallback);
check_curl_result(res, "DOWNLOAD cannot set progress function: ");
@@ -2107,6 +2127,14 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
// Verify MD5 sum if requested:
//
if (hash) {
+ if (res != CURLE_OK) {
+ status.SetError(cmStrCat(
+ "DOWNLOAD cannot compute hash on failed download\n"
+ " status: [",
+ static_cast<int>(res), ";\"", ::curl_easy_strerror(res), "\"]"));
+ return false;
+ }
+
std::string actualHash = hash->HashFile(file);
if (actualHash.empty()) {
status.SetError("DOWNLOAD cannot compute hash on downloaded file");
@@ -2130,11 +2158,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
expectedHash,
"]\n"
" actual hash: [",
- actualHash,
- "]\n"
- " status: [",
- static_cast<int>(res), ";\"",
- ::curl_easy_strerror(res), "\"]\n"));
+ actualHash, "]\n"));
return false;
}
}
@@ -2364,7 +2388,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
res = ::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
check_curl_result(res, "UPLOAD cannot set noprogress value: ");
- res = ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,
+ res = ::curl_easy_setopt(curl, CM_CURLOPT_XFERINFOFUNCTION,
cmFileUploadProgressCallback);
check_curl_result(res, "UPLOAD cannot set progress function: ");
@@ -2458,11 +2482,13 @@ void AddEvaluationFile(const std::string& inputName,
{
cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace();
- cmGeneratorExpression outputGe(lfbt);
+ cmGeneratorExpression outputGe(*status.GetMakefile().GetCMakeInstance(),
+ lfbt);
std::unique_ptr<cmCompiledGeneratorExpression> outputCge =
outputGe.Parse(outputExpr);
- cmGeneratorExpression conditionGe(lfbt);
+ cmGeneratorExpression conditionGe(*status.GetMakefile().GetCMakeInstance(),
+ lfbt);
std::unique_ptr<cmCompiledGeneratorExpression> conditionCge =
conditionGe.Parse(condition);
@@ -3398,20 +3424,29 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args,
}
int compressionLevel = 0;
+ int minCompressionLevel = 0;
+ int maxCompressionLevel = 9;
+ if (compress == cmSystemTools::TarCompressZstd) {
+ maxCompressionLevel = 19;
+ }
+
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"));
+ status.SetError(
+ cmStrCat("compression level ", parsedArgs.CompressionLevel, " for ",
+ parsedArgs.Compression, " should be in range ",
+ minCompressionLevel, " to ", maxCompressionLevel));
cmSystemTools::SetFatalErrorOccurred();
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"));
+ if (compressionLevel < minCompressionLevel ||
+ compressionLevel > maxCompressionLevel) {
+ status.SetError(
+ cmStrCat("compression level ", parsedArgs.CompressionLevel, " for ",
+ parsedArgs.Compression, " should be in range ",
+ minCompressionLevel, " to ", maxCompressionLevel));
cmSystemTools::SetFatalErrorOccurred();
return false;
}
diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx
index 99f6885..c23a99c 100644
--- a/Source/cmFileLockPool.cxx
+++ b/Source/cmFileLockPool.cxx
@@ -15,7 +15,7 @@ cmFileLockPool::~cmFileLockPool() = default;
void cmFileLockPool::PushFunctionScope()
{
- this->FunctionScopes.push_back(ScopePool());
+ this->FunctionScopes.emplace_back();
}
void cmFileLockPool::PopFunctionScope()
@@ -26,7 +26,7 @@ void cmFileLockPool::PopFunctionScope()
void cmFileLockPool::PushFileScope()
{
- this->FileScopes.push_back(ScopePool());
+ this->FileScopes.emplace_back();
}
void cmFileLockPool::PopFileScope()
diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx
index d6665a2..b96ba6e 100644
--- a/Source/cmFileSet.cxx
+++ b/Source/cmFileSet.cxx
@@ -78,9 +78,10 @@ bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis)
return false;
}
-cmFileSet::cmFileSet(std::string name, std::string type,
+cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
cmFileSetVisibility visibility)
- : Name(std::move(name))
+ : CMakeInstance(cmakeInstance)
+ , Name(std::move(name))
, Type(std::move(type))
, Visibility(visibility)
{
@@ -113,7 +114,7 @@ cmFileSet::CompileFileEntries() const
for (auto const& entry : this->FileEntries) {
for (auto const& ex : cmExpandedList(entry.Value)) {
- cmGeneratorExpression ge(entry.Backtrace);
+ cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
auto cge = ge.Parse(ex);
result.push_back(std::move(cge));
}
@@ -129,7 +130,7 @@ cmFileSet::CompileDirectoryEntries() const
for (auto const& entry : this->DirectoryEntries) {
for (auto const& ex : cmExpandedList(entry.Value)) {
- cmGeneratorExpression ge(entry.Backtrace);
+ cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
auto cge = ge.Parse(ex);
result.push_back(std::move(cge));
}
diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h
index 5357e77..54d430c 100644
--- a/Source/cmFileSet.h
+++ b/Source/cmFileSet.h
@@ -17,6 +17,7 @@ struct cmGeneratorExpressionDAGChecker;
class cmGeneratorTarget;
class cmLocalGenerator;
class cmMakefile;
+class cmake;
enum class cmFileSetVisibility
{
@@ -33,7 +34,7 @@ bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis);
class cmFileSet
{
public:
- cmFileSet(std::string name, std::string type,
+ cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
cmFileSetVisibility visibility);
const std::string& GetName() const { return this->Name; }
@@ -77,6 +78,7 @@ public:
static bool IsValidName(const std::string& name);
private:
+ cmake& CMakeInstance;
std::string Name;
std::string Type;
cmFileSetVisibility Visibility;
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index b8d345f..4df81d5 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -344,7 +344,7 @@ struct entry_to_remove
{
if (cmValue to_skip = makefile->GetDefinition(
cmStrCat("_CMAKE_SYSTEM_PREFIX_PATH_", name, "_PREFIX_COUNT"))) {
- cmStrToLong(to_skip, &count);
+ cmStrToLong(*to_skip, &count);
}
if (cmValue prefix_value = makefile->GetDefinition(
cmStrCat("_CMAKE_SYSTEM_PREFIX_PATH_", name, "_PREFIX_VALUE"))) {
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 3f8378b..c1b82ab 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -377,6 +377,10 @@ private:
# pragma diag_suppress 1222 // invalid error number (3288, but works anyway)
# define CM_LCC_DIAG_SUPPRESS_3288
# pragma diag_suppress 3288 // parameter was declared but never referenced
+# define CM_LCC_DIAG_SUPPRESS_3301
+# pragma diag_suppress 3301 // parameter was declared but never referenced
+# define CM_LCC_DIAG_SUPPRESS_3308
+# pragma diag_suppress 3308 // parameter was declared but never referenced
#endif
void ResetGenerator()
@@ -421,6 +425,16 @@ bool TryGeneratedPaths(CallbackFn&& filesCollector,
return false;
}
+#ifdef CM_LCC_DIAG_SUPPRESS_3308
+# undef CM_LCC_DIAG_SUPPRESS_3308
+# pragma diag_default 3308
+#endif
+
+#ifdef CM_LCC_DIAG_SUPPRESS_3301
+# undef CM_LCC_DIAG_SUPPRESS_3301
+# pragma diag_default 3301
+#endif
+
#ifdef CM_LCC_DIAG_SUPPRESS_3288
# undef CM_LCC_DIAG_SUPPRESS_3288
# pragma diag_default 3288
@@ -2190,7 +2204,7 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable()
std::string install_path_to_remove;
if (cmValue to_skip = this->Makefile->GetDefinition(
"_CMAKE_SYSTEM_PREFIX_PATH_INSTALL_PREFIX_COUNT")) {
- cmStrToLong(to_skip, &install_prefix_count);
+ cmStrToLong(*to_skip, &install_prefix_count);
}
if (cmValue install_value = this->Makefile->GetDefinition(
"_CMAKE_SYSTEM_PREFIX_PATH_INSTALL_PREFIX_VALUE")) {
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index c72d6a7..133bf5f 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -27,7 +27,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding)
cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
bool quiet, Encoding encoding)
: cmGeneratedFileStreamBase(name)
- , Stream(this->TempName.c_str())
+ , Stream(this->TempName.c_str()) // NOLINT(cmake-use-cmsys-fstream)
{
// Check if the file opened.
if (!*this && !quiet) {
@@ -67,10 +67,11 @@ cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name,
// Open the temporary output file.
if (binaryFlag) {
- this->Stream::open(this->TempName.c_str(),
- std::ios::out | std::ios::binary);
+ this->Stream::open( // NOLINT(cmake-use-cmsys-fstream)
+ this->TempName.c_str(), std::ios::out | std::ios::binary);
} else {
- this->Stream::open(this->TempName.c_str());
+ this->Stream::open( // NOLINT(cmake-use-cmsys-fstream)
+ this->TempName.c_str());
}
// Check if the file opened.
@@ -87,7 +88,7 @@ bool cmGeneratedFileStream::Close()
this->Okay = !this->fail();
// Close the temporary output file.
- this->Stream::close();
+ this->Stream::close(); // NOLINT(cmake-use-cmsys-fstream)
// Remove the temporary file (possibly by renaming to the real file).
return this->cmGeneratedFileStreamBase::Close();
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index f988e54..c5ae31b 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGeneratorExpression.h"
+#include <algorithm>
#include <cassert>
#include <memory>
#include <utility>
@@ -13,11 +14,15 @@
#include "cmGeneratorExpressionEvaluator.h"
#include "cmGeneratorExpressionLexer.h"
#include "cmGeneratorExpressionParser.h"
+#include "cmLocalGenerator.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmake.h"
-cmGeneratorExpression::cmGeneratorExpression(cmListFileBacktrace backtrace)
- : Backtrace(std::move(backtrace))
+cmGeneratorExpression::cmGeneratorExpression(cmake& cmakeInstance,
+ cmListFileBacktrace backtrace)
+ : CMakeInstance(cmakeInstance)
+ , Backtrace(std::move(backtrace))
{
}
@@ -29,7 +34,8 @@ std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse(
std::string input) const
{
return std::unique_ptr<cmCompiledGeneratorExpression>(
- new cmCompiledGeneratorExpression(this->Backtrace, std::move(input)));
+ new cmCompiledGeneratorExpression(this->CMakeInstance, this->Backtrace,
+ std::move(input)));
}
std::string cmGeneratorExpression::Evaluate(
@@ -39,7 +45,13 @@ std::string cmGeneratorExpression::Evaluate(
cmGeneratorTarget const* currentTarget, std::string const& language)
{
if (Find(input) != std::string::npos) {
- cmCompiledGeneratorExpression cge(cmListFileBacktrace(), std::move(input));
+#ifndef CMAKE_BOOTSTRAP
+ auto profilingRAII = lg->GetCMakeInstance()->CreateProfilingEntry(
+ "genex_compile_eval", input);
+#endif
+
+ cmCompiledGeneratorExpression cge(*lg->GetCMakeInstance(),
+ cmListFileBacktrace(), std::move(input));
return cge.Evaluate(lg, config, headTarget, dagChecker, currentTarget,
language);
}
@@ -97,10 +109,15 @@ const std::string& cmCompiledGeneratorExpression::EvaluateWithContext(
}
cmCompiledGeneratorExpression::cmCompiledGeneratorExpression(
- cmListFileBacktrace backtrace, std::string input)
+ cmake& cmakeInstance, cmListFileBacktrace backtrace, std::string input)
: Backtrace(std::move(backtrace))
, Input(std::move(input))
{
+#ifndef CMAKE_BOOTSTRAP
+ auto profilingRAII =
+ cmakeInstance.CreateProfilingEntry("genex_compile", this->Input);
+#endif
+
cmGeneratorExpressionLexer l;
std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input);
this->NeedsEvaluation = l.GetSawGeneratorExpression();
@@ -210,23 +227,33 @@ static std::string stripExportInterface(
while (true) {
std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos);
std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos);
+ std::string::size_type lPos =
+ input.find("$<BUILD_LOCAL_INTERFACE:", lastPos);
- if (bPos == std::string::npos && iPos == std::string::npos) {
+ pos = std::min({ bPos, iPos, lPos });
+ if (pos == std::string::npos) {
break;
}
- if (bPos == std::string::npos) {
- pos = iPos;
- } else if (iPos == std::string::npos) {
- pos = bPos;
+ result += input.substr(lastPos, pos - lastPos);
+ enum class FoundGenex
+ {
+ BuildInterface,
+ InstallInterface,
+ BuildLocalInterface,
+ } foundGenex = FoundGenex::BuildInterface;
+ if (pos == bPos) {
+ foundGenex = FoundGenex::BuildInterface;
+ pos += cmStrLen("$<BUILD_INTERFACE:");
+ } else if (pos == iPos) {
+ foundGenex = FoundGenex::InstallInterface;
+ pos += cmStrLen("$<INSTALL_INTERFACE:");
+ } else if (pos == lPos) {
+ foundGenex = FoundGenex::BuildLocalInterface;
+ pos += cmStrLen("$<BUILD_LOCAL_INTERFACE:");
} else {
- pos = (bPos < iPos) ? bPos : iPos;
+ assert(false && "Invalid position found");
}
-
- result += input.substr(lastPos, pos - lastPos);
- const bool gotInstallInterface = input[pos + 2] == 'I';
- pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1
- : sizeof("$<BUILD_INTERFACE:") - 1;
nestingLevel = 1;
const char* c = input.c_str() + pos;
const char* const cStart = c;
@@ -242,10 +269,10 @@ static std::string stripExportInterface(
continue;
}
if (context == cmGeneratorExpression::BuildInterface &&
- !gotInstallInterface) {
+ foundGenex == FoundGenex::BuildInterface) {
result += input.substr(pos, c - cStart);
} else if (context == cmGeneratorExpression::InstallInterface &&
- gotInstallInterface) {
+ foundGenex == FoundGenex::InstallInterface) {
const std::string content = input.substr(pos, c - cStart);
if (resolveRelative) {
prefixItems(content, result, "${_IMPORT_PREFIX}/");
@@ -258,9 +285,18 @@ static std::string stripExportInterface(
}
const std::string::size_type traversed = (c - cStart) + 1;
if (!*c) {
- result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:"
- : "$<BUILD_INTERFACE:") +
- input.substr(pos, traversed);
+ auto remaining = input.substr(pos, traversed);
+ switch (foundGenex) {
+ case FoundGenex::BuildInterface:
+ result = cmStrCat(result, "$<BUILD_INTERFACE:", remaining);
+ break;
+ case FoundGenex::InstallInterface:
+ result = cmStrCat(result, "$<INSTALL_INTERFACE:", remaining);
+ break;
+ case FoundGenex::BuildLocalInterface:
+ result = cmStrCat(result, "$<BUILD_LOCAL_INTERFACE:", remaining);
+ break;
+ }
}
pos += traversed;
lastPos = pos;
@@ -370,7 +406,7 @@ void cmGeneratorExpression::ReplaceInstallPrefix(
while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) !=
std::string::npos) {
- std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1;
+ std::string::size_type endPos = pos + cmStrLen("$<INSTALL_PREFIX>");
input.replace(pos, endPos - pos, replacement);
lastPos = endPos;
}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 188993f..e22b8ab 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -12,10 +12,11 @@
#include <vector>
#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+class cmake;
class cmCompiledGeneratorExpression;
class cmGeneratorTarget;
-class cmLocalGenerator;
struct cmGeneratorExpressionContext;
struct cmGeneratorExpressionDAGChecker;
struct cmGeneratorExpressionEvaluator;
@@ -33,7 +34,8 @@ class cmGeneratorExpression
{
public:
/** Construct. */
- cmGeneratorExpression(cmListFileBacktrace backtrace = cmListFileBacktrace());
+ cmGeneratorExpression(cmake& cmakeInstance,
+ cmListFileBacktrace backtrace = cmListFileBacktrace());
~cmGeneratorExpression();
cmGeneratorExpression(cmGeneratorExpression const&) = delete;
@@ -82,6 +84,7 @@ public:
const std::string& replacement);
private:
+ cmake& CMakeInstance;
cmListFileBacktrace Backtrace;
};
@@ -152,7 +155,8 @@ private:
cmGeneratorExpressionContext& context,
cmGeneratorExpressionDAGChecker* dagChecker) const;
- cmCompiledGeneratorExpression(cmListFileBacktrace backtrace,
+ cmCompiledGeneratorExpression(cmake& cmakeInstance,
+ cmListFileBacktrace backtrace,
std::string input);
friend class cmGeneratorExpression;
@@ -184,7 +188,8 @@ public:
std::string config,
cmGeneratorTarget const* headTarget,
std::string language = std::string())
- : LocalGenerator(localGenerator)
+ : GeneratorExpression(*localGenerator->GetCMakeInstance())
+ , LocalGenerator(localGenerator)
, Config(std::move(config))
, HeadTarget(headTarget)
, Language(std::move(language))
diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx
index 8f3ed4d..817437e 100644
--- a/Source/cmGeneratorExpressionEvaluationFile.cxx
+++ b/Source/cmGeneratorExpressionEvaluationFile.cxx
@@ -165,7 +165,7 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg)
}
cmListFileBacktrace lfbt = this->OutputFileExpr->GetBacktrace();
- cmGeneratorExpression contentGE(lfbt);
+ cmGeneratorExpression contentGE(*lg->GetCMakeInstance(), lfbt);
std::unique_ptr<cmCompiledGeneratorExpression> inputExpression =
contentGE.Parse(inputContent);
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index fec309c..b239408 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -4,8 +4,14 @@
#include <sstream>
+#ifndef CMAKE_BOOTSTRAP
+# include <cm3p/json/value.h>
+#endif
+
#include "cmGeneratorExpressionContext.h"
#include "cmGeneratorExpressionNode.h"
+#include "cmLocalGenerator.h"
+#include "cmake.h"
GeneratorExpressionContent::GeneratorExpressionContent(
const char* startContent, size_t length)
@@ -61,6 +67,12 @@ std::string GeneratorExpressionContent::Evaluate(
cmGeneratorExpressionContext* context,
cmGeneratorExpressionDAGChecker* dagChecker) const
{
+#ifndef CMAKE_BOOTSTRAP
+ auto evalProfilingRAII =
+ context->LG->GetCMakeInstance()->CreateProfilingEntry(
+ "genex_eval", this->GetOriginalExpression());
+#endif
+
std::string identifier;
{
for (const auto& pExprEval : this->IdentifierChildren) {
@@ -101,7 +113,24 @@ std::string GeneratorExpressionContent::Evaluate(
return std::string();
}
- return node->Evaluate(parameters, context, this, dagChecker);
+ {
+#ifndef CMAKE_BOOTSTRAP
+ auto execProfilingRAII =
+ context->LG->GetCMakeInstance()->CreateProfilingEntry(
+ "genex_exec", identifier, [&parameters]() -> Json::Value {
+ Json::Value args = Json::objectValue;
+ if (!parameters.empty()) {
+ args["genexArgs"] = Json::arrayValue;
+ for (auto const& parameter : parameters) {
+ args["genexArgs"].append(parameter);
+ }
+ }
+ return args;
+ });
+#endif
+
+ return node->Evaluate(parameters, context, this, dagChecker);
+ }
}
std::string GeneratorExpressionContent::EvaluateParameters(
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 45d5a83..6595323 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -57,7 +57,7 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
cmGeneratorExpressionDAGChecker* dagChecker,
cmGeneratorTarget const* currentTarget)
{
- cmGeneratorExpression ge(context->Backtrace);
+ cmGeneratorExpression ge(*lg->GetCMakeInstance(), context->Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem);
cge->SetQuiet(context->Quiet);
@@ -114,6 +114,8 @@ static const struct OneNode buildInterfaceNode;
static const struct ZeroNode installInterfaceNode;
+static const struct OneNode buildLocalInterfaceNode;
+
struct BooleanOpNode : public cmGeneratorExpressionNode
{
BooleanOpNode(const char* op_, const char* successVal_,
@@ -1350,12 +1352,30 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
}
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;
+ bool firstParam = true;
for (auto const& param : parameters) {
+ if (!configValidator.find(param)) {
+ if (firstParam) {
+ reportError(context, content->GetOriginalExpression(),
+ "Expression syntax not recognized.");
+ return std::string();
+ }
+ // for backwards compat invalid config names are only errors as
+ // the first parameter
+ std::ostringstream e;
+ /* clang-format off */
+ e << "Warning evaluating generator expression:\n"
+ << " " << content->GetOriginalExpression() << "\n"
+ << "The config name of \"" << param << "\" is invalid";
+ /* clang-format on */
+ context->LG->GetCMakeInstance()->IssueMessage(
+ MessageType::WARNING, e.str(), context->Backtrace);
+ }
+
+ firstParam = false;
if (context->Config.empty()) {
if (param.empty()) {
return "1";
@@ -1386,6 +1406,14 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
return "1";
}
}
+ } else if (!suffix.empty()) {
+ // There is no explicit mapping for the tested config, so use
+ // the configuration of the imported location that was selected.
+ for (auto const& param : parameters) {
+ if (cmStrCat('_', cmSystemTools::UpperCase(param)) == suffix) {
+ return "1";
+ }
+ }
}
}
}
@@ -1970,7 +1998,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
}
return std::string();
}
- target = context->LG->FindGeneratorTargetToUse(targetName);
+ cmLocalGenerator const* lg = context->CurrentTarget
+ ? context->CurrentTarget->GetLocalGenerator()
+ : context->LG;
+ target = lg->FindGeneratorTargetToUse(targetName);
if (!target) {
std::ostringstream e;
@@ -3320,6 +3351,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
{ "GENEX_EVAL", &genexEvalNode },
{ "BUILD_INTERFACE", &buildInterfaceNode },
{ "INSTALL_INTERFACE", &installInterfaceNode },
+ { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode },
{ "INSTALL_PREFIX", &installPrefixNode },
{ "JOIN", &joinNode },
{ "LINK_ONLY", &linkOnlyNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 7d43eb1..5e352b2 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -241,15 +241,16 @@ private:
std::unique_ptr<
cmGeneratorTarget::
- TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std::
- string>&
+ TargetPropertyEntry> static CreateTargetPropertyEntry(cmake& cmakeInstance,
+ const BT<
+ std::string>&
propertyValue,
bool
evaluateForBuildsystem =
false)
{
if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) {
- cmGeneratorExpression ge(propertyValue.Backtrace);
+ cmGeneratorExpression ge(cmakeInstance, propertyValue.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(propertyValue.Value);
cge->SetEvaluateForBuildsystem(evaluateForBuildsystem);
@@ -262,12 +263,13 @@ std::unique_ptr<
}
static void CreatePropertyGeneratorExpressions(
- cmBTStringRange entries,
+ cmake& cmakeInstance, cmBTStringRange entries,
std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items,
bool evaluateForBuildsystem = false)
{
for (auto const& entry : entries) {
- items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem));
+ items.push_back(
+ CreateTargetPropertyEntry(cmakeInstance, entry, evaluateForBuildsystem));
}
}
@@ -343,29 +345,36 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
this->GlobalGenerator->ComputeTargetObjectDirectory(this);
- CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetIncludeDirectoriesEntries(),
this->IncludeDirectoriesEntries);
- CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetCompileOptionsEntries(),
this->CompileOptionsEntries);
- CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetCompileFeaturesEntries(),
this->CompileFeaturesEntries);
- CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetCompileDefinitionsEntries(),
this->CompileDefinitionsEntries);
- CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetLinkOptionsEntries(),
this->LinkOptionsEntries);
- CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetLinkDirectoriesEntries(),
this->LinkDirectoriesEntries);
- CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(),
+ CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(),
+ t->GetPrecompileHeadersEntries(),
this->PrecompileHeadersEntries);
- CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
- this->SourceEntries, true);
+ CreatePropertyGeneratorExpressions(
+ *lg->GetCMakeInstance(), t->GetSourceEntries(), this->SourceEntries, true);
this->PolicyMap = t->GetPolicyMap();
@@ -563,12 +572,7 @@ std::string cmGeneratorTarget::GetFilePrefix(
cmValue 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;
+ return this->GetFullNameInternalComponents(config, artifact).prefix;
}
std::string cmGeneratorTarget::GetFileSuffix(
const std::string& config, cmStateEnums::ArtifactType artifact) const
@@ -577,12 +581,7 @@ std::string cmGeneratorTarget::GetFileSuffix(
cmValue 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;
+ return this->GetFullNameInternalComponents(config, artifact).suffix;
}
std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
@@ -740,6 +739,14 @@ void cmGeneratorTarget::ClearSourcesCache()
this->VisitedConfigsForObjects.clear();
this->LinkImplMap.clear();
this->LinkImplUsageRequirementsOnlyMap.clear();
+ this->IncludeDirectoriesCache.clear();
+ this->CompileOptionsCache.clear();
+ this->CompileDefinitionsCache.clear();
+ this->PrecompileHeadersCache.clear();
+ this->LinkOptionsCache.clear();
+ this->LinkDirectoriesCache.clear();
+ this->RuntimeBinaryFullNameCache.clear();
+ this->ImportLibraryFullNameCache.clear();
}
void cmGeneratorTarget::ClearLinkInterfaceCache()
@@ -753,6 +760,7 @@ void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
this->SourceEntries.insert(
before ? this->SourceEntries.begin() : this->SourceEntries.end(),
CreateTargetPropertyEntry(
+ *this->LocalGenerator->GetCMakeInstance(),
BT<std::string>(src, this->Makefile->GetBacktrace()), true));
this->ClearSourcesCache();
}
@@ -780,6 +788,7 @@ void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
before ? this->IncludeDirectoriesEntries.begin()
: this->IncludeDirectoriesEntries.end(),
CreateTargetPropertyEntry(
+ *this->Makefile->GetCMakeInstance(),
BT<std::string>(src, this->Makefile->GetBacktrace()), true));
}
@@ -1653,7 +1662,8 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget,
headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
lib.Target);
std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
- cmGeneratorExpression ge(lib.Backtrace);
+ cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(),
+ lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
@@ -2162,23 +2172,21 @@ std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
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);
cmValue config_name = this->GetProperty(configProp);
if (cmNonempty(config_name)) {
- return prefix + *config_name + ".pdb";
+ NameComponents const& components = GetFullNameInternalComponents(
+ config, cmStateEnums::RuntimeBinaryArtifact);
+ return components.prefix + *config_name + ".pdb";
}
cmValue name = this->GetProperty("COMPILE_PDB_NAME");
if (cmNonempty(name)) {
- return prefix + *name + ".pdb";
+ NameComponents const& components = GetFullNameInternalComponents(
+ config, cmStateEnums::RuntimeBinaryArtifact);
+ return components.prefix + *name + ".pdb";
}
return "";
@@ -2921,11 +2929,11 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
}
}
-void cmGeneratorTarget::GetFullNameComponents(
- std::string& prefix, std::string& base, std::string& suffix,
- const std::string& config, cmStateEnums::ArtifactType artifact) const
+cmGeneratorTarget::NameComponents const&
+cmGeneratorTarget::GetFullNameComponents(
+ std::string const& config, cmStateEnums::ArtifactType artifact) const
{
- this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+ return this->GetFullNameInternalComponents(config, artifact);
}
std::string cmGeneratorTarget::BuildBundleDirectory(
@@ -3554,7 +3562,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink,
if (ipoEnabled && compileOrLink == cmBuildStep::Link) {
if (cmValue cudaIPOFlags =
this->Makefile->GetDefinition("CMAKE_CUDA_LINK_OPTIONS_IPO")) {
- flags += cudaIPOFlags;
+ flags += *cudaIPOFlags;
}
}
@@ -3708,6 +3716,24 @@ std::string cmGeneratorTarget::GetCreateRuleVariable(
return "";
}
+//----------------------------------------------------------------------------
+std::string cmGeneratorTarget::GetClangTidyExportFixesDirectory(
+ const std::string& lang) const
+{
+ cmValue val =
+ this->GetProperty(cmStrCat(lang, "_CLANG_TIDY_EXPORT_FIXES_DIR"));
+ if (!cmNonempty(val)) {
+ return {};
+ }
+
+ std::string path = *val;
+ if (!cmSystemTools::FileIsFullPath(path)) {
+ path =
+ cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', path);
+ }
+ return cmSystemTools::CollapseFullPath(path);
+}
+
namespace {
void processIncludeDirectories(cmGeneratorTarget const* tgt,
EvaluatedTargetPropertyEntries& entries,
@@ -3817,6 +3843,13 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt,
std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
const std::string& config, const std::string& lang) const
{
+ ConfigAndLanguage cacheKey(config, lang);
+ {
+ auto it = this->IncludeDirectoriesCache.find(cacheKey);
+ if (it != this->IncludeDirectoriesCache.end()) {
+ return it->second;
+ }
+ }
std::vector<BT<std::string>> includes;
std::unordered_set<std::string> uniqueIncludes;
@@ -3891,6 +3924,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
processIncludeDirectories(this, entries, includes, uniqueIncludes,
debugIncludes);
+ this->IncludeDirectoriesCache.emplace(cacheKey, includes);
return includes;
}
@@ -4068,6 +4102,13 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result,
std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
std::string const& config, std::string const& language) const
{
+ ConfigAndLanguage cacheKey(config, language);
+ {
+ auto it = this->CompileOptionsCache.find(cacheKey);
+ if (it != this->CompileOptionsCache.end()) {
+ return it->second;
+ }
+ }
std::vector<BT<std::string>> result;
std::unordered_set<std::string> uniqueOptions;
@@ -4094,6 +4135,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
processOptions(this, entries, result, uniqueOptions, debugOptions,
"compile options", OptionsParse::Shell);
+ CompileOptionsCache.emplace(cacheKey, result);
return result;
}
@@ -4155,6 +4197,13 @@ void cmGeneratorTarget::GetCompileDefinitions(
std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
std::string const& config, std::string const& language) const
{
+ ConfigAndLanguage cacheKey(config, language);
+ {
+ auto it = this->CompileDefinitionsCache.find(cacheKey);
+ if (it != this->CompileDefinitionsCache.end()) {
+ return it->second;
+ }
+ }
std::vector<BT<std::string>> list;
std::unordered_set<std::string> uniqueOptions;
@@ -4192,7 +4241,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
}
case cmPolicies::OLD: {
std::unique_ptr<TargetPropertyEntry> entry =
- CreateTargetPropertyEntry(*configProp);
+ CreateTargetPropertyEntry(
+ *this->LocalGenerator->GetCMakeInstance(), *configProp);
entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
this, config, language, &dagChecker, *entry));
} break;
@@ -4207,12 +4257,20 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
processOptions(this, entries, list, uniqueOptions, debugDefines,
"compile definitions", OptionsParse::None);
+ this->CompileDefinitionsCache.emplace(cacheKey, list);
return list;
}
std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
const std::string& config, const std::string& language) const
{
+ ConfigAndLanguage cacheKey(config, language);
+ {
+ auto it = this->PrecompileHeadersCache.find(cacheKey);
+ if (it != this->PrecompileHeadersCache.end()) {
+ return it->second;
+ }
+ }
std::unordered_set<std::string> uniqueOptions;
cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
@@ -4240,6 +4298,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
processOptions(this, entries, list, uniqueOptions, debugDefines,
"precompile headers", OptionsParse::None);
+ this->PrecompileHeadersCache.emplace(cacheKey, list);
return list;
}
@@ -4600,6 +4659,14 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
std::string const& config, std::string const& language) const
{
+ ConfigAndLanguage cacheKey(
+ config, cmStrCat(language, this->IsDeviceLink() ? "-device" : ""));
+ {
+ auto it = this->LinkOptionsCache.find(cacheKey);
+ if (it != this->LinkOptionsCache.end()) {
+ return it->second;
+ }
+ }
std::vector<BT<std::string>> result;
std::unordered_set<std::string> uniqueOptions;
@@ -4677,7 +4744,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
// Last step: replace "LINKER:" prefixed elements by
// actual linker wrapper
- return this->ResolveLinkerWrapper(result, language);
+ result = this->ResolveLinkerWrapper(result, language);
+
+ this->LinkOptionsCache.emplace(cacheKey, result);
+ return result;
}
std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper(
@@ -4776,13 +4846,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
EvaluatedTargetPropertyEntries entries;
if (cmValue 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));
- }
+ std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry(
+ *this->LocalGenerator->GetCMakeInstance(), *linkOptions);
+ entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+ this, config, language, &dagChecker, *entry));
}
processOptions(this, entries, result, uniqueOptions, false,
"static library link options", OptionsParse::Shell);
@@ -4876,6 +4943,14 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
std::string const& config, std::string const& language) const
{
+ ConfigAndLanguage cacheKey(
+ config, cmStrCat(language, this->IsDeviceLink() ? "-device" : ""));
+ {
+ auto it = this->LinkDirectoriesCache.find(cacheKey);
+ if (it != this->LinkDirectoriesCache.end()) {
+ return it->second;
+ }
+ }
std::vector<BT<std::string>> result;
std::unordered_set<std::string> uniqueDirectories;
@@ -4905,6 +4980,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
processLinkDirectories(this, entries, result, uniqueDirectories,
debugDirectories);
+ this->LinkDirectoriesCache.emplace(cacheKey, result);
return result;
}
@@ -4931,8 +5007,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
std::vector<std::string> depends = cmExpandedList(*linkDepends);
for (const auto& depend : depends) {
- std::unique_ptr<TargetPropertyEntry> entry =
- CreateTargetPropertyEntry(depend);
+ std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry(
+ *this->LocalGenerator->GetCMakeInstance(), depend);
entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
this, config, language, &dagChecker, *entry));
}
@@ -5175,32 +5251,33 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
}
// Get the components of the library name.
- std::string prefix;
- std::string suffix;
- this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, targetNames.Base, suffix);
+ NameComponents const& components = this->GetFullNameInternalComponents(
+ config, cmStateEnums::RuntimeBinaryArtifact);
// The library name.
- targetNames.Output = prefix + targetNames.Base + suffix;
+ targetNames.Base = components.base;
+ targetNames.Output =
+ components.prefix + targetNames.Base + components.suffix;
if (this->IsFrameworkOnApple()) {
- targetNames.Real = prefix;
+ targetNames.Real = components.prefix;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
targetNames.Real += "Versions/";
targetNames.Real += this->GetFrameworkVersion();
targetNames.Real += "/";
}
- targetNames.Real += targetNames.Base + suffix;
- targetNames.SharedObject = targetNames.Real + suffix;
+ targetNames.Real += targetNames.Base + components.suffix;
+ targetNames.SharedObject = targetNames.Real + components.suffix;
} else {
// The library's soname.
- this->ComputeVersionedName(targetNames.SharedObject, prefix,
- targetNames.Base, suffix, targetNames.Output,
- soversion);
+ this->ComputeVersionedName(targetNames.SharedObject, components.prefix,
+ targetNames.Base, components.suffix,
+ targetNames.Output, soversion);
// The library's real name on disk.
- this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base,
- suffix, targetNames.Output, version);
+ this->ComputeVersionedName(targetNames.Real, components.prefix,
+ targetNames.Base, components.suffix,
+ targetNames.Output, version);
}
// The import library name.
@@ -5244,17 +5321,17 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
#endif
// Get the components of the executable name.
- std::string prefix;
- std::string suffix;
- this->GetFullNameInternal(config, cmStateEnums::RuntimeBinaryArtifact,
- prefix, targetNames.Base, suffix);
+ NameComponents const& components = this->GetFullNameInternalComponents(
+ config, cmStateEnums::RuntimeBinaryArtifact);
// The executable name.
- targetNames.Output = prefix + targetNames.Base + suffix;
+ targetNames.Base = components.base;
+ targetNames.Output =
+ components.prefix + targetNames.Base + components.suffix;
// The executable's real name on disk.
#if defined(__CYGWIN__)
- targetNames.Real = prefix + targetNames.Base;
+ targetNames.Real = components.prefix + targetNames.Base;
#else
targetNames.Real = targetNames.Output;
#endif
@@ -5263,7 +5340,7 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
targetNames.Real += *version;
}
#if defined(__CYGWIN__)
- targetNames.Real += suffix;
+ targetNames.Real += components.suffix;
#endif
// The import library name.
@@ -5279,11 +5356,9 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames(
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;
+ NameComponents const& components =
+ this->GetFullNameInternalComponents(config, artifact);
+ return components.prefix + components.base + components.suffix;
}
std::string cmGeneratorTarget::ImportedGetLocation(
@@ -5301,19 +5376,27 @@ std::string cmGeneratorTarget::GetFullNameImported(
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
+cmGeneratorTarget::NameComponents const&
+cmGeneratorTarget::GetFullNameInternalComponents(
+ std::string const& config, cmStateEnums::ArtifactType artifact) const
{
+ assert(artifact == cmStateEnums::RuntimeBinaryArtifact ||
+ artifact == cmStateEnums::ImportLibraryArtifact);
+ FullNameCache& cache = artifact == cmStateEnums::RuntimeBinaryArtifact
+ ? RuntimeBinaryFullNameCache
+ : ImportLibraryFullNameCache;
+ auto search = cache.find(config);
+ if (search != cache.end()) {
+ return search->second;
+ }
// 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;
+ NameComponents components;
+ components.base = this->GetName();
+ return cache.emplace(config, std::move(components)).first->second;
}
const bool isImportedLibraryArtifact =
@@ -5322,12 +5405,14 @@ void cmGeneratorTarget::GetFullNameInternal(
// 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;
+ return cache.emplace(config, NameComponents()).first->second;
}
+ NameComponents parts;
+ std::string& outPrefix = parts.prefix;
+ std::string& outBase = parts.base;
+ std::string& outSuffix = parts.suffix;
+
// retrieve prefix and suffix
std::string ll = this->GetLinkerLanguage(config);
cmValue targetPrefix = this->GetFilePrefixInternal(config, artifact, ll);
@@ -5388,6 +5473,8 @@ void cmGeneratorTarget::GetFullNameInternal(
// Append the suffix.
outSuffix = targetSuffix ? *targetSuffix : "";
+
+ return cache.emplace(config, std::move(parts)).first->second;
}
std::string cmGeneratorTarget::GetLinkerLanguage(
@@ -5423,11 +5510,8 @@ std::string cmGeneratorTarget::GetPDBOutputName(
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);
+ NameComponents const& parts = this->GetFullNameInternalComponents(
+ config, cmStateEnums::RuntimeBinaryArtifact);
std::vector<std::string> props;
std::string configUpper = cmSystemTools::UpperCase(config);
@@ -5441,11 +5525,10 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const
for (std::string const& p : props) {
if (cmValue outName = this->GetProperty(p)) {
- base = *outName;
- break;
+ return parts.prefix + *outName + ".pdb";
}
}
- return prefix + base + ".pdb";
+ return parts.prefix + parts.base + ".pdb";
}
std::string cmGeneratorTarget::GetObjectDirectory(
@@ -5532,7 +5615,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
} else if (cmHasLiteralPrefix(*location, "Resources/")) {
flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource;
if (stripResources) {
- flags.MacFolder += strlen("Resources/");
+ flags.MacFolder += cmStrLen("Resources/");
}
} else {
flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
@@ -5901,7 +5984,7 @@ std::string valueAsString<std::string>(std::string value)
template <>
std::string valueAsString<cmValue>(cmValue value)
{
- return value ? value : std::string("(unset)");
+ return value ? *value : std::string("(unset)");
}
template <>
std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
@@ -6705,7 +6788,7 @@ 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);
+ cmDirectoryId const dirId = n.substr(cmStrLen(CMAKE_DIRECTORY_ID_SEP));
if (dirId.String.empty()) {
lg = this->LocalGenerator;
return true;
@@ -6756,7 +6839,8 @@ void cmGeneratorTarget::ExpandLinkItems(
cmMakefile const* mf = this->LocalGenerator->GetMakefile();
LookupLinkItemScope scope{ this->LocalGenerator };
for (BT<std::string> const& entry : entries) {
- cmGeneratorExpression ge(entry.Backtrace);
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(),
+ entry.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value);
cge->SetEvaluateForBuildsystem(true);
std::vector<std::string> libs = cmExpandedList(
@@ -8195,7 +8279,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
break;
}
}
- cmGeneratorExpression ge(entry.Backtrace);
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(),
+ entry.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> const cge =
ge.Parse(entry.Value);
cge->SetEvaluateForBuildsystem(true);
@@ -8515,9 +8600,14 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType(
// lib
// 2. empty propval: add /clr as flag, mixed unmanaged/managed
// target, has import lib
- // 3. any value (safe,pure): add /clr:[propval] as flag, target with
+ // 3. netcore propval: add /clr:netcore as flag, mixed
+ // unmanaged/managed target, has import lib.
+ // 4. any value (safe,pure): add /clr:[propval] as flag, target with
// managed code only, no import lib
- return propval.empty() ? ManagedType::Mixed : ManagedType::Managed;
+ if (propval.empty() || propval == "netcore") {
+ return ManagedType::Mixed;
+ }
+ return ManagedType::Managed;
}
cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType(
@@ -8770,6 +8860,15 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
return filename;
}
+bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
+{
+ auto sources = cmGeneratorTarget::GetSourceFiles(config);
+ return std::any_of(sources.begin(), sources.end(),
+ [](BT<cmSourceFile*> const& sf) -> bool {
+ return sf.Value->GetLanguage() == "Fortran"_s;
+ });
+}
+
bool cmGeneratorTarget::HaveCxx20ModuleSources() const
{
auto const& fs_names = this->Target->GetAllFileSetNames();
@@ -8849,3 +8948,101 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
}
}
}
+
+bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang,
+ std::string const& config) const
+{
+ if (lang != "CXX"_s) {
+ return false;
+ }
+ return this->HaveCxxModuleSupport(config) == Cxx20SupportLevel::Supported &&
+ this->GetGlobalGenerator()->CheckCxxModuleSupport();
+}
+
+bool cmGeneratorTarget::NeedDyndep(std::string const& lang,
+ std::string const& config) const
+{
+ return lang == "Fortran"_s || this->NeedCxxModuleSupport(lang, config);
+}
+
+cmFileSet const* cmGeneratorTarget::GetFileSetForSource(
+ std::string const& config, cmSourceFile const* sf) const
+{
+ this->BuildFileSetInfoCache(config);
+
+ auto const& path = sf->GetFullPath();
+ auto const& per_config = this->Configs[config];
+
+ auto const fsit = per_config.FileSetCache.find(path);
+ if (fsit == per_config.FileSetCache.end()) {
+ return nullptr;
+ }
+ return fsit->second;
+}
+
+bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
+ std::string const& config,
+ cmSourceFile const* sf) const
+{
+ bool const needDyndep = this->NeedDyndep(lang, config);
+ if (!needDyndep) {
+ return false;
+ }
+ auto const* fs = this->GetFileSetForSource(config, sf);
+ if (fs &&
+ (fs->GetType() == "CXX_MODULES"_s ||
+ fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) {
+ return true;
+ }
+ auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES");
+ if (sfProp.IsSet()) {
+ return sfProp.IsOn();
+ }
+ auto const tgtProp = this->GetProperty("CXX_SCAN_FOR_MODULES");
+ if (tgtProp.IsSet()) {
+ return tgtProp.IsOn();
+ }
+ return true;
+}
+
+void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const
+{
+ auto& per_config = this->Configs[config];
+
+ if (per_config.BuiltFileSetCache) {
+ return;
+ }
+
+ auto const* tgt = this->Target;
+
+ for (auto const& name : tgt->GetAllFileSetNames()) {
+ auto const* file_set = tgt->GetFileSet(name);
+ if (!file_set) {
+ tgt->GetMakefile()->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("Target \"", tgt->GetName(),
+ "\" is tracked to have file set \"", name,
+ "\", but it was not found."));
+ continue;
+ }
+
+ auto fileEntries = file_set->CompileFileEntries();
+ auto directoryEntries = file_set->CompileDirectoryEntries();
+ auto directories = file_set->EvaluateDirectoryEntries(
+ directoryEntries, this->LocalGenerator, config, this);
+
+ std::map<std::string, std::vector<std::string>> files;
+ for (auto const& entry : fileEntries) {
+ file_set->EvaluateFileEntry(directories, files, entry,
+ this->LocalGenerator, config, this);
+ }
+
+ for (auto const& it : files) {
+ for (auto const& filename : it.second) {
+ per_config.FileSetCache[filename] = file_set;
+ }
+ }
+ }
+
+ per_config.BuiltFileSetCache = true;
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 25e6a81..afd9da4 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -26,6 +26,7 @@
enum class cmBuildStep;
class cmComputeLinkInformation;
class cmCustomCommand;
+class cmFileSet;
class cmGlobalGenerator;
class cmLocalGenerator;
class cmMakefile;
@@ -347,10 +348,16 @@ public:
/** 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;
+ struct NameComponents
+ {
+ std::string prefix;
+ std::string base;
+ std::string suffix;
+ };
+ NameComponents const& GetFullNameComponents(
+ std::string const& config,
+ cmStateEnums::ArtifactType artifact =
+ cmStateEnums::RuntimeBinaryArtifact) const;
/** Append to @a base the bundle directory hierarchy up to a certain @a level
* and return it. */
@@ -489,6 +496,20 @@ public:
std::string GetCreateRuleVariable(std::string const& lang,
std::string const& config) const;
+ std::string GetClangTidyExportFixesDirectory(const std::string& lang) const;
+
+private:
+ using ConfigAndLanguage = std::pair<std::string, std::string>;
+ using ConfigAndLanguageToBTStrings =
+ std::map<ConfigAndLanguage, std::vector<BT<std::string>>>;
+ mutable ConfigAndLanguageToBTStrings IncludeDirectoriesCache;
+ mutable ConfigAndLanguageToBTStrings CompileOptionsCache;
+ mutable ConfigAndLanguageToBTStrings CompileDefinitionsCache;
+ mutable ConfigAndLanguageToBTStrings PrecompileHeadersCache;
+ mutable ConfigAndLanguageToBTStrings LinkOptionsCache;
+ mutable ConfigAndLanguageToBTStrings LinkDirectoriesCache;
+
+public:
/** Get the include directories for this target. */
std::vector<BT<std::string>> GetIncludeDirectories(
const std::string& config, const std::string& lang) const;
@@ -925,10 +946,14 @@ private:
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;
+
+ using FullNameCache = std::map<std::string, NameComponents>;
+
+ mutable FullNameCache RuntimeBinaryFullNameCache;
+ mutable FullNameCache ImportLibraryFullNameCache;
+
+ NameComponents const& GetFullNameInternalComponents(
+ std::string const& config, cmStateEnums::ArtifactType artifact) const;
mutable std::string LinkerLanguage;
using LinkClosureMapType = std::map<std::string, LinkClosure>;
@@ -1200,6 +1225,8 @@ public:
cmGeneratorTarget const* t2) const;
};
+ bool HaveFortranSources(std::string const& config) const;
+
// C++20 module support queries.
/**
@@ -1229,4 +1256,21 @@ public:
// Check C++ module status for the target.
void CheckCxxModuleStatus(std::string const& config) const;
+
+ bool NeedCxxModuleSupport(std::string const& lang,
+ std::string const& config) const;
+ bool NeedDyndep(std::string const& lang, std::string const& config) const;
+ cmFileSet const* GetFileSetForSource(std::string const& config,
+ cmSourceFile const* sf) const;
+ bool NeedDyndepForSource(std::string const& lang, std::string const& config,
+ cmSourceFile const* sf) const;
+
+private:
+ void BuildFileSetInfoCache(std::string const& config) const;
+ struct InfoByConfig
+ {
+ bool BuiltFileSetCache = false;
+ std::map<std::string, cmFileSet const*> FileSetCache;
+ };
+ mutable std::map<std::string, InfoByConfig> Configs;
};
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 138d3f1..8471dfe 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -9,6 +9,8 @@
#include <utility>
#include <vector>
+#include <cm/optional>
+
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
@@ -411,9 +413,8 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
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);
+ if (cm::optional<std::string> comment = ccg.GetComment()) {
+ std::string echocmd = cmStrCat("echo ", *comment);
cmdLines.push_back(std::move(echocmd));
}
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 776ee40..2fd7f8a 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -60,11 +60,10 @@ cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf)
return std::unique_ptr<cmLocalGenerator>(std::move(lg));
}
-void cmGlobalBorlandMakefileGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalBorlandMakefileGenerator::GetDocumentation()
{
- entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName();
- entry.Brief = "Generates Borland makefiles.";
+ return { cmGlobalBorlandMakefileGenerator::GetActualName(),
+ "Generates Borland makefiles." };
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index a280b81..049d6ba 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -13,7 +13,6 @@
class cmLocalGenerator;
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalBorlandMakefileGenerator
* \brief Write a Borland makefiles.
@@ -38,7 +37,7 @@ public:
static std::string GetActualName() { return "Borland Makefiles"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
//! Create a local generator appropriate to this Global Generator
std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
index 3ae66f0..7a44452 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -2,11 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalCommonGenerator.h"
+#include <algorithm>
#include <memory>
#include <utility>
#include <cmext/algorithm>
+#include <cmsys/Glob.hxx>
+
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
@@ -14,6 +17,7 @@
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
#include "cmake.h"
@@ -124,3 +128,23 @@ std::string cmGlobalCommonGenerator::GetEditCacheCommand() const
cmValue edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND");
return edit_cmd ? *edit_cmd : std::string();
}
+
+void cmGlobalCommonGenerator::RemoveUnknownClangTidyExportFixesFiles() const
+{
+ for (auto const& dir : this->ClangTidyExportFixesDirs) {
+ cmsys::Glob g;
+ g.SetRecurse(true);
+ g.SetListDirs(false);
+ g.FindFiles(cmStrCat(dir, "/*.yaml"));
+ for (auto const& file : g.GetFiles()) {
+ if (!this->ClangTidyExportFixesFiles.count(file) &&
+ !std::any_of(this->ClangTidyExportFixesFiles.begin(),
+ this->ClangTidyExportFixesFiles.end(),
+ [&file](const std::string& knownFile) -> bool {
+ return cmSystemTools::SameFile(file, knownFile);
+ })) {
+ cmSystemTools::RemoveFile(file);
+ }
+ }
+ }
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
index fed9ce8..fa42674 100644
--- a/Source/cmGlobalCommonGenerator.h
+++ b/Source/cmGlobalCommonGenerator.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <map>
+#include <set>
#include <string>
#include <vector>
@@ -42,9 +43,21 @@ public:
std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t,
const std::string& config);
+ void AddClangTidyExportFixesDir(const std::string& dir)
+ {
+ this->ClangTidyExportFixesDirs.insert(dir);
+ }
+ void AddClangTidyExportFixesFile(const std::string& file)
+ {
+ this->ClangTidyExportFixesFiles.insert(file);
+ }
protected:
virtual bool SupportsDirectConsole() const { return true; }
const char* GetEditCacheTargetName() const override { return "edit_cache"; }
std::string GetEditCacheCommand() const override;
+
+ std::set<std::string> ClangTidyExportFixesDirs;
+ std::set<std::string> ClangTidyExportFixesFiles;
+ void RemoveUnknownClangTidyExportFixesFiles() const;
};
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index c2bf888..4cfec22 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -4,11 +4,13 @@
#include <algorithm>
#include <cassert>
+#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <initializer_list>
+#include <iomanip>
#include <iterator>
#include <sstream>
#include <utility>
@@ -827,7 +829,8 @@ void cmGlobalGenerator::EnableLanguage(
"No " << compilerName << " could be found.\n"
;
/* clang-format on */
- } else if ((lang != "RC") && (lang != "ASM_MASM")) {
+ } else if ((lang != "RC") && (lang != "ASM_MARMASM") &&
+ (lang != "ASM_MASM")) {
if (!cmSystemTools::FileIsFullPath(*compilerFile)) {
/* clang-format off */
noCompiler <<
@@ -946,7 +949,7 @@ void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
// 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 << "either the environment variable \"" << *envVar << "\" or ";
}
os << "the CMake cache entry CMAKE_" << lang
<< "_COMPILER "
@@ -1302,6 +1305,8 @@ void cmGlobalGenerator::CreateLocalGenerators()
void cmGlobalGenerator::Configure()
{
+ auto startTime = std::chrono::steady_clock::now();
+
this->FirstTimeProgress = 0.0f;
this->ClearGeneratorMembers();
this->NextDeferId = 0;
@@ -1349,20 +1354,17 @@ void cmGlobalGenerator::Configure()
"number of local generators",
cmStateEnums::INTERNAL);
+ auto endTime = std::chrono::steady_clock::now();
+
if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) {
std::ostringstream msg;
if (cmSystemTools::GetErrorOccurredFlag()) {
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";
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+ endTime - startTime);
+ msg << "Configuring done (" << std::fixed << std::setprecision(1)
+ << ms.count() / 1000.0L << "s)";
}
this->CMakeInstance->UpdateProgress(msg.str(), -1);
}
@@ -1438,6 +1440,19 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
return false;
}
+void cmGlobalGenerator::CxxModuleSupportCheck() const
+{
+ 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.");
+ }
+}
+
void cmGlobalGenerator::ComputeBuildFileGenerators()
{
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
@@ -1592,10 +1607,14 @@ bool cmGlobalGenerator::Compute()
void cmGlobalGenerator::Generate()
{
+ auto startTime = std::chrono::steady_clock::now();
+
// Create a map from local generator to the complete set of targets
// it builds by default.
this->InitializeProgressMarks();
+ this->DiagnosedCxxModuleSupport = false;
+
this->ProcessEvaluationFiles();
this->CMakeInstance->UpdateProgress("Generating", 0.1f);
@@ -1672,7 +1691,13 @@ void cmGlobalGenerator::Generate()
w.str());
}
- this->CMakeInstance->UpdateProgress("Generating done", -1);
+ auto endTime = std::chrono::steady_clock::now();
+ auto ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
+ std::ostringstream msg;
+ msg << "Generating done (" << std::fixed << std::setprecision(1)
+ << ms.count() / 1000.0L << "s)";
+ this->CMakeInstance->UpdateProgress(msg.str(), -1);
}
bool cmGlobalGenerator::ComputeTargetDepends()
@@ -2024,7 +2049,7 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
- config, defaultBuildOptions, false,
+ config, defaultBuildOptions, true,
this->TryCompileTimeout);
}
@@ -2943,19 +2968,18 @@ std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
bool cmGlobalGenerator::UseFolderProperty() const
{
- cmValue prop =
+ const cmValue prop =
this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
- // If this property is defined, let the setter turn this on or off...
- //
+ // 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;
+ // If CMP0143 is NEW `treat` "USE_FOLDERS" as ON. Otherwise `treat` it as OFF
+ assert(!this->Makefiles.empty());
+ return (this->Makefiles[0]->GetPolicyStatus(cmPolicies::CMP0143) ==
+ cmPolicies::NEW);
}
void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti,
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 076b041..66ab752 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -157,6 +157,8 @@ public:
virtual bool InspectConfigTypeVariables() { return true; }
+ virtual bool CheckCxxModuleSupport() { return false; }
+
bool Compute();
virtual void AddExtraIDETargets() {}
@@ -621,6 +623,8 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const;
+ void CxxModuleSupportCheck() const;
+
/// @brief Qt AUTOMOC/UIC/RCC target generation
/// @return true on success
bool QtAutoGen();
@@ -728,6 +732,8 @@ private:
std::map<std::string, int> LanguageToLinkerPreference;
std::map<std::string, std::string> LanguageToOriginalSharedLibFlags;
+ mutable bool DiagnosedCxxModuleSupport = false;
+
// Deferral id generation.
size_t NextDeferId = 0;
diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h
index d6ababb..a935079 100644
--- a/Source/cmGlobalGeneratorFactory.h
+++ b/Source/cmGlobalGeneratorFactory.h
@@ -4,6 +4,10 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmDocumentationEntry.h" // IWYU pragma: export
+
+// TODO The following headers are parts of the `cmGlobalGeneratorFactory`
+// public API, so could be defined as export to IWYU
#include <string>
#include <vector>
@@ -11,7 +15,6 @@
class cmGlobalGenerator;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalGeneratorFactory
* \brief Responable for creating cmGlobalGenerator instances
@@ -28,7 +31,7 @@ public:
const std::string& n, bool allowArch, cmake* cm) const = 0;
/** Get the documentation entry for this factory */
- virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0;
+ virtual cmDocumentationEntry GetDocumentation() const = 0;
/** Get the names of the current registered generators */
virtual std::vector<std::string> GetGeneratorNames() const = 0;
@@ -47,7 +50,7 @@ public:
virtual std::string GetDefaultPlatformName() const = 0;
};
-template <class T>
+template <typename T>
class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory
{
public:
@@ -62,21 +65,19 @@ public:
}
/** Get the documentation entry for this factory */
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- T::GetDocumentation(entry);
+ return T::GetDocumentation();
}
/** Get the names of the current registered generators */
std::vector<std::string> GetGeneratorNames() const override
{
- std::vector<std::string> names;
- names.push_back(T::GetActualName());
- return names;
+ return { T::GetActualName() };
}
std::vector<std::string> GetGeneratorNamesWithPlatform() const override
{
- return std::vector<std::string>();
+ return {};
}
/** Determine whether or not this generator supports toolsets */
@@ -89,8 +90,8 @@ public:
std::vector<std::string> GetKnownPlatforms() const override
{
// default is no platform supported
- return std::vector<std::string>();
+ return {};
}
- std::string GetDefaultPlatformName() const override { return std::string(); }
+ std::string GetDefaultPlatformName() const override { return {}; }
};
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 9c334a5..3da15f6 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -15,7 +15,6 @@
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
-#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGhsMultiGpj.h"
@@ -58,11 +57,12 @@ cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf)
cm::make_unique<cmLocalGhsMultiGenerator>(this, mf));
}
-void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalGhsMultiGenerator::GetDocumentation()
{
- entry.Name = GetActualName();
- entry.Brief =
- "Generates Green Hills MULTI files (experimental, work-in-progress).";
+ return {
+ GetActualName(),
+ "Generates Green Hills MULTI files (experimental, work-in-progress)."
+ };
}
void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory(
@@ -100,10 +100,10 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
cmValue prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
/* check if the toolset changed from last generate */
- if (cmNonempty(prevTool) && !cmSystemTools::ComparePath(gbuild, prevTool)) {
+ if (cmNonempty(prevTool) && !cmSystemTools::ComparePath(gbuild, *prevTool)) {
std::string const& e =
cmStrCat("toolset build tool: ", gbuild,
- "\nDoes not match the previously used build tool: ", prevTool,
+ "\nDoes not match the previously used build tool: ", *prevTool,
"\nEither remove the CMakeCache.txt file and CMakeFiles "
"directory or choose a different binary directory.");
mf->IssueMessage(MessageType::FATAL_ERROR, e);
@@ -354,7 +354,7 @@ void cmGlobalGhsMultiGenerator::WriteProjectLine(
* unsupported target type and should be skipped.
*/
if (projFile && projType) {
- std::string path = cmSystemTools::RelativePath(rootBinaryDir, projFile);
+ std::string path = cmSystemTools::RelativePath(rootBinaryDir, *projFile);
fout << path;
fout << ' ' << *projType << '\n';
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index aa68d3b..4a79610 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -18,7 +18,6 @@ class cmGeneratorTarget;
class cmLocalGenerator;
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
{
@@ -46,7 +45,7 @@ public:
std::string GetName() const override { return GetActualName(); }
/// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
/**
* Utilized by the generator factory to determine if this generator
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 1a625cc..f1d4d09 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -6,7 +6,6 @@
#include <cmext/algorithm>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
@@ -36,11 +35,10 @@ void cmGlobalJOMMakefileGenerator::EnableLanguage(
this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
}
-void cmGlobalJOMMakefileGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalJOMMakefileGenerator::GetDocumentation()
{
- entry.Name = cmGlobalJOMMakefileGenerator::GetActualName();
- entry.Brief = "Generates JOM makefiles.";
+ return { cmGlobalJOMMakefileGenerator::GetActualName(),
+ "Generates JOM makefiles." };
}
void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os,
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index 332d1cf..5e74875 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -13,7 +13,6 @@
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalJOMMakefileGenerator
* \brief Write a JOM makefiles.
@@ -39,7 +38,7 @@ public:
static std::string GetActualName() { return "NMake Makefiles JOM"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
/**
* Try to determine system information such as shared library
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index d4ff1e0..e543aea 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -4,7 +4,6 @@
#include "cmsys/FStream.hxx"
-#include "cmDocumentationEntry.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
@@ -53,9 +52,8 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage(
}
}
-void cmGlobalMSYSMakefileGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalMSYSMakefileGenerator::GetDocumentation()
{
- entry.Name = cmGlobalMSYSMakefileGenerator::GetActualName();
- entry.Brief = "Generates MSYS makefiles.";
+ return { cmGlobalMSYSMakefileGenerator::GetActualName(),
+ "Generates MSYS makefiles." };
}
diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h
index 586487f..ee9a4ee 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.h
+++ b/Source/cmGlobalMSYSMakefileGenerator.h
@@ -11,7 +11,6 @@
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalMSYSMakefileGenerator
* \brief Write a NMake makefiles.
@@ -29,21 +28,21 @@ public:
}
//! Get the name for the generator.
- virtual std::string GetName() const
+ std::string GetName() const override
{
return cmGlobalMSYSMakefileGenerator::GetActualName();
}
static std::string GetActualName() { return "MSYS Makefiles"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
/**
* Try to determine system information such as shared library
* extension, pthreads, byte order etc.
*/
- virtual void EnableLanguage(std::vector<std::string> const& languages,
- cmMakefile*, bool optional);
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
private:
std::string FindMinGW(std::string const& makeloc);
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index 5a7edae..a0a52d3 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalMinGWMakefileGenerator.h"
-#include "cmDocumentationEntry.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmSystemTools.h"
@@ -19,9 +18,8 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm)
cm->GetState()->SetMinGWMake(true);
}
-void cmGlobalMinGWMakefileGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalMinGWMakefileGenerator::GetDocumentation()
{
- entry.Name = cmGlobalMinGWMakefileGenerator::GetActualName();
- entry.Brief = "Generates a make file for use with mingw32-make.";
+ return { cmGlobalMinGWMakefileGenerator::GetActualName(),
+ "Generates a make file for use with mingw32-make." };
}
diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h
index 92d495c..7dd968b 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.h
+++ b/Source/cmGlobalMinGWMakefileGenerator.h
@@ -11,7 +11,6 @@
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalMinGWMakefileGenerator
* \brief Write a NMake makefiles.
@@ -28,12 +27,12 @@ public:
new cmGlobalGeneratorSimpleFactory<cmGlobalMinGWMakefileGenerator>());
}
//! Get the name for the generator.
- virtual std::string GetName() const
+ std::string GetName() const override
{
return cmGlobalMinGWMakefileGenerator::GetActualName();
}
static std::string GetActualName() { return "MinGW Makefiles"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
};
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index eabacf6..cb53850 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -8,7 +8,6 @@
#include "cmsys/RegularExpression.hxx"
-#include "cmDocumentationEntry.h"
#include "cmDuration.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
@@ -80,11 +79,10 @@ void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures()
cmSystemTools::OP_LESS, this->NMakeVersion, "9");
}
-void cmGlobalNMakeMakefileGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalNMakeMakefileGenerator::GetDocumentation()
{
- entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName();
- entry.Brief = "Generates NMake makefiles.";
+ return { cmGlobalNMakeMakefileGenerator::GetActualName(),
+ "Generates NMake makefiles." };
}
void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
@@ -128,12 +126,8 @@ void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
// nmake does not support parallel build level
// see https://msdn.microsoft.com/en-us/library/afyyse50.aspx
-
- /* clang-format off */
- os <<
- "Warning: NMake does not support parallel builds. "
- "Ignoring parallel build command line option.\n";
- /* clang-format on */
+ os << "Warning: NMake does not support parallel builds. "
+ "Ignoring parallel build command line option.\n";
}
this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index b3574eb..436ebca 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -15,7 +15,6 @@
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalNMakeMakefileGenerator
* \brief Write a NMake makefiles.
@@ -45,7 +44,7 @@ public:
}
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
/**
* Try to determine system information such as shared library
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 980ff2f..93aa30a 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -8,6 +8,7 @@
#include <cstdio>
#include <functional>
#include <sstream>
+#include <tuple>
#include <utility>
#include <cm/iterator>
@@ -25,8 +26,7 @@
#include "cmsys/FStream.hxx"
#include "cmCxxModuleMapper.h"
-#include "cmDocumentationEntry.h"
-#include "cmFileSet.h"
+#include "cmDyndepCollation.h"
#include "cmFortranParser.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpressionEvaluationFile.h"
@@ -554,10 +554,10 @@ codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
return this->NinjaExpectedEncoding;
}
-void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalNinjaGenerator::GetDocumentation()
{
- entry.Name = cmGlobalNinjaGenerator::GetActualName();
- entry.Brief = "Generates build.ninja files.";
+ return { cmGlobalNinjaGenerator::GetActualName(),
+ "Generates build.ninja files." };
}
// Implemented in all cmGlobaleGenerator sub-classes.
@@ -585,14 +585,16 @@ void cmGlobalNinjaGenerator::Generate()
}
for (auto& it : this->Configs) {
- it.second.TargetDependsClosures.clear();
+ it.second.TargetDependsClosureLocalOutputs.clear();
}
this->InitOutputPathPrefix();
this->TargetAll = this->NinjaOutputPath("all");
this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt");
this->DisableCleandead = false;
- this->DiagnosedCxxModuleSupport = false;
+ this->DiagnosedCxxModuleNinjaSupport = false;
+ this->ClangTidyExportFixesDirs.clear();
+ this->ClangTidyExportFixesFiles.clear();
this->PolicyCMP0058 =
this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus(
@@ -633,6 +635,8 @@ void cmGlobalNinjaGenerator::Generate()
{
this->CleanMetaData();
}
+
+ this->RemoveUnknownClangTidyExportFixesFiles();
}
void cmGlobalNinjaGenerator::CleanMetaData()
@@ -854,18 +858,12 @@ bool cmGlobalNinjaGenerator::CheckLanguages(
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.");
- }
+ this->CxxModuleSupportCheck();
if (this->NinjaSupportsDyndepsCxx) {
return true;
}
+ bool const diagnose = !this->DiagnosedCxxModuleNinjaSupport &&
+ !this->CMakeInstance->GetIsInTryCompile();
if (diagnose) {
std::ostringstream e;
/* clang-format off */
@@ -874,7 +872,8 @@ bool cmGlobalNinjaGenerator::CheckCxxModuleSupport()
"using Ninja version \n"
" " << this->NinjaVersion << "\n"
"due to lack of required features. "
- "Ninja " << RequiredNinjaVersionForDyndepsCxx() << " or higher is required."
+ "Ninja " << RequiredNinjaVersionForDyndepsCxx() <<
+ " or higher is required."
;
/* clang-format on */
this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str());
@@ -1175,7 +1174,8 @@ void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName,
}
void cmGlobalNinjaGenerator::AddCXXCompileCommand(
- const std::string& commandLine, const std::string& sourceFile)
+ const std::string& commandLine, const std::string& sourceFile,
+ const std::string& objPath)
{
// Compute Ninja's build file path.
std::string buildFileDir =
@@ -1209,7 +1209,9 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
<< R"( "command": ")"
<< cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
<< R"( "file": ")"
- << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
+ << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\",\n"
+ << R"( "output": ")"
+ << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n"
<< "}";
/* clang-format on */
}
@@ -1258,7 +1260,7 @@ 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
+ // for frameworks, we want the real name, not sample name
// frameworks always appear versioned, and the build.ninja
// will always attempt to manage symbolic links instead
// of letting cmOSXBundleGenerator do it.
@@ -1364,70 +1366,85 @@ 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);
-}
+ struct Entry
+ {
+ Entry(cmGeneratorTarget const* target_, std::string config_,
+ std::string fileConfig_)
+ : target(target_)
+ , config(std::move(config_))
+ , fileConfig(std::move(fileConfig_))
+ {
+ }
-void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
- cmGeneratorTarget const* target, cmNinjaOuts& outputs,
- const std::string& config, const std::string& fileConfig, bool genexOutput,
- bool omit_self)
-{
+ bool operator<(Entry const& other) const
+ {
+ return std::tie(target, config, fileConfig) <
+ std::tie(other.target, other.config, other.fileConfig);
+ }
- // try to locate the target in the cache
- ByConfig::TargetDependsClosureKey key{
- target,
- config,
- genexOutput,
+ cmGeneratorTarget const* target;
+ std::string config;
+ std::string fileConfig;
};
- 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)) {
+
+ cmNinjaOuts outputSet;
+ std::vector<Entry> stack;
+ stack.emplace_back(target, config, fileConfig);
+ std::set<Entry> seen = { stack.back() };
+
+ do {
+ Entry entry = std::move(stack.back());
+ stack.pop_back();
+
+ // generate the outputs of the target itself, if applicable
+ if (entry.target != target) {
+ // try to locate the target in the cache
+ ByConfig::TargetDependsClosureKey localCacheKey{
+ entry.target,
+ entry.config,
+ genexOutput,
+ };
+ auto& configs = this->Configs[entry.fileConfig];
+ auto lb =
+ configs.TargetDependsClosureLocalOutputs.lower_bound(localCacheKey);
+
+ if (lb == configs.TargetDependsClosureLocalOutputs.end() ||
+ lb->first != localCacheKey) {
+ cmNinjaDeps outs;
+ this->AppendTargetOutputs(entry.target, outs, entry.config,
+ DependOnTargetArtifact);
+ configs.TargetDependsClosureLocalOutputs.emplace_hint(
+ lb, localCacheKey, outs);
+ for (auto& value : outs) {
+ outputSet.emplace(std::move(value));
+ }
+ } else {
+ outputSet.insert(lb->second.begin(), lb->second.end());
+ }
+ }
+
+ // push next dependencies
+ for (const auto& dep_target : this->GetTargetDirectDepends(entry.target)) {
if (!dep_target->IsInBuildSystem()) {
continue;
}
- if (!this->IsSingleConfigUtility(target) &&
+ if (!this->IsSingleConfigUtility(entry.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);
+ auto emplaceRes = seen.emplace(
+ dep_target, dep_target.IsCross() ? entry.fileConfig : entry.config,
+ entry.fileConfig);
+ if (emplaceRes.second) {
+ stack.emplace_back(*emplaceRes.first);
}
}
- 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());
+ } while (!stack.empty());
+ cm::append(outputs, outputSet);
}
void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
@@ -2102,6 +2119,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
}
std::vector<std::string> byproducts;
+ byproducts.reserve(this->CrossConfigs.size());
for (auto const& config : this->CrossConfigs) {
byproducts.push_back(
this->BuildAlias(GetByproductsForCleanTargetName(), config));
@@ -2476,45 +2494,6 @@ cm::optional<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran(
}
}
-struct CxxModuleFileSet
-{
- std::string Name;
- std::string RelativeDirectory;
- std::string SourcePath;
- std::string Type;
- cmFileSetVisibility Visibility;
- cm::optional<std::string> Destination;
-};
-
-struct CxxModuleBmiInstall
-{
- std::string Component;
- std::string Destination;
- bool ExcludeFromAll;
- bool Optional;
- std::string Permissions;
- std::string MessageLevel;
- std::string ScriptLocation;
-};
-
-struct CxxModuleExport
-{
- std::string Name;
- std::string Destination;
- std::string Prefix;
- std::string CxxModuleInfoDir;
- std::string Namespace;
- bool Install;
-};
-
-struct cmGlobalNinjaGenerator::CxxModuleExportInfo
-{
- std::map<std::string, CxxModuleFileSet> ObjectToFileSet;
- cm::optional<CxxModuleBmiInstall> BmiInstallation;
- std::vector<CxxModuleExport> Exports;
- std::string Config;
-};
-
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,
@@ -2522,7 +2501,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
std::string const& arg_lang, std::string const& arg_modmapfmt,
- CxxModuleExportInfo const& export_info)
+ cmCxxModuleExportInfo const& export_info)
{
// Setup path conversions.
{
@@ -2558,8 +2537,13 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmStrCat(linked_target_dir, '/', arg_lang, "Modules.json");
Json::Value ltm;
cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
+ if (!ltmf) {
+ cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to open ",
+ ltmn, " for module information"));
+ return false;
+ }
Json::Reader reader;
- if (ltmf && !reader.parse(ltmf, ltm, false)) {
+ if (!reader.parse(ltmf, ltm, false)) {
cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ",
linked_target_dir,
reader.getFormattedErrorMessages()));
@@ -2614,6 +2598,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cm::optional<CxxModuleMapFormat> modmap_fmt;
if (arg_modmapfmt.empty()) {
// nothing to do.
+ } else if (arg_modmapfmt == "clang") {
+ modmap_fmt = CxxModuleMapFormat::Clang;
} else if (arg_modmapfmt == "gcc") {
modmap_fmt = CxxModuleMapFormat::Gcc;
} else if (arg_modmapfmt == "msvc") {
@@ -2757,279 +2743,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmGeneratedFileStream tmf(target_mods_file);
tmf << target_module_info;
- bool result = true;
-
- // Fortran doesn't support any of the file-set or BMI installation considered
- // below.
- if (arg_lang != "Fortran"_s) {
- // Prepare the export information blocks.
- std::string const config_upper =
- cmSystemTools::UpperCase(export_info.Config);
- std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>,
- CxxModuleExport const*>>
- exports;
- for (auto const& exp : export_info.Exports) {
- std::unique_ptr<cmGeneratedFileStream> properties;
-
- std::string const export_dir =
- cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
- std::string const property_file_path = cmStrCat(
- export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake");
- properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
-
- // Set up the preamble.
- *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
- << "\"\n"
- << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper
- << '\n';
-
- exports.emplace_back(std::move(properties), &exp);
+ cmDyndepMetadataCallbacks cb;
+ cb.ModuleFile =
+ [mod_files](std::string const& name) -> cm::optional<std::string> {
+ auto m = mod_files.find(name);
+ if (m != mod_files.end()) {
+ return m->second;
}
+ return {};
+ };
- std::unique_ptr<cmGeneratedFileStream> bmi_install_script;
- if (export_info.BmiInstallation) {
- bmi_install_script = cm::make_unique<cmGeneratedFileStream>(
- export_info.BmiInstallation->ScriptLocation);
- }
-
- auto cmEscape = [](cm::string_view str) {
- return cmOutputConverter::EscapeForCMake(
- str, cmOutputConverter::WrapQuotes::NoWrap);
- };
- auto install_destination =
- [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> {
- if (cmSystemTools::FileIsFullPath(dest)) {
- return std::make_pair(true, cmEscape(dest));
- }
- return std::make_pair(false,
- cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest)));
- };
-
- // public/private requirement tracking.
- std::set<std::string> private_modules;
- std::map<std::string, std::set<std::string>> public_source_requires;
-
- for (cmScanDepInfo const& object : objects) {
- // Convert to forward slashes.
- auto output_path = object.PrimaryOutput;
-# ifdef _WIN32
- cmSystemTools::ConvertToUnixSlashes(output_path);
-# endif
- // Find the fileset for this object.
- auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path);
- bool const has_provides = !object.Provides.empty();
- if (fileset_info_itr == export_info.ObjectToFileSet.end()) {
- // If it provides anything, it should have a `CXX_MODULES` or
- // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present.
- if (has_provides) {
- // Take the first module provided to provide context.
- auto const& provides = object.Provides[0];
- char const* ok_types = "`CXX_MODULES`";
- if (provides.LogicalName.find(':') != std::string::npos) {
- ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
- "it is not `export`ed)";
- }
- cmSystemTools::Error(
- cmStrCat("Output ", object.PrimaryOutput, " provides the `",
- provides.LogicalName,
- "` module but it is not found in a `FILE_SET` of type ",
- ok_types));
- result = false;
- }
-
- // This object file does not provide anything, so nothing more needs to
- // be done.
- continue;
- }
-
- auto const& file_set = fileset_info_itr->second;
-
- // Verify the fileset type for the object.
- if (file_set.Type == "CXX_MODULES"_s) {
- if (!has_provides) {
- cmSystemTools::Error(cmStrCat(
- "Output ", object.PrimaryOutput,
- " is of type `CXX_MODULES` but does not provide a module"));
- result = false;
- continue;
- }
- } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) {
- if (!has_provides) {
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath,
- " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
- "provide a module"));
- result = false;
- continue;
- }
- auto const& provides = object.Provides[0];
- if (provides.LogicalName.find(':') == std::string::npos) {
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath,
- " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not "
- "provide a module partition"));
- result = false;
- continue;
- }
- } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) {
- // TODO.
- } else {
- if (has_provides) {
- auto const& provides = object.Provides[0];
- char const* ok_types = "`CXX_MODULES`";
- if (provides.LogicalName.find(':') != std::string::npos) {
- ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if "
- "it is not `export`ed)";
- }
- cmSystemTools::Error(cmStrCat(
- "Source ", file_set.SourcePath, " provides the `",
- provides.LogicalName, "` C++ module but is of type `",
- file_set.Type, "` module but must be of type ", ok_types));
- result = false;
- }
-
- // Not a C++ module; ignore.
- continue;
- }
-
- if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) {
- // Nothing needs to be conveyed about non-`PUBLIC` modules.
- for (auto const& p : object.Provides) {
- private_modules.insert(p.LogicalName);
- }
- continue;
- }
-
- // The module is public. Record what it directly requires.
- {
- auto& reqs = public_source_requires[file_set.SourcePath];
- for (auto const& r : object.Requires) {
- reqs.insert(r.LogicalName);
- }
- }
-
- // Write out properties and install rules for any exports.
- for (auto const& p : object.Provides) {
- bool bmi_dest_is_abs = false;
- std::string bmi_destination;
- if (export_info.BmiInstallation) {
- auto dest =
- install_destination(export_info.BmiInstallation->Destination);
- bmi_dest_is_abs = dest.first;
- bmi_destination = cmStrCat(dest.second, '/');
- }
-
- std::string install_bmi_path;
- std::string build_bmi_path;
- auto m = mod_files.find(p.LogicalName);
- if (m != mod_files.end()) {
- install_bmi_path =
- cmStrCat(bmi_destination,
- cmEscape(cmSystemTools::GetFilenameName(m->second)));
- build_bmi_path = cmEscape(m->second);
- }
-
- for (auto const& exp : exports) {
- std::string iface_source;
- if (exp.second->Install && file_set.Destination) {
- auto dest = install_destination(*file_set.Destination);
- iface_source = cmStrCat(
- dest.second, '/', cmEscape(file_set.RelativeDirectory),
- cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
- } else {
- iface_source = cmEscape(file_set.SourcePath);
- }
-
- std::string bmi_path;
- if (exp.second->Install && export_info.BmiInstallation) {
- bmi_path = install_bmi_path;
- } else if (!exp.second->Install) {
- bmi_path = build_bmi_path;
- }
-
- if (iface_source.empty()) {
- // No destination for the C++ module source; ignore this property
- // value.
- continue;
- }
-
- *exp.first << " \"" << cmEscape(p.LogicalName) << '='
- << iface_source;
- if (!bmi_path.empty()) {
- *exp.first << ',' << bmi_path;
- }
- *exp.first << "\"\n";
- }
-
- if (bmi_install_script) {
- auto const& bmi_install = *export_info.BmiInstallation;
-
- *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \""
- << cmEscape(bmi_install.Component) << '\"';
- if (!bmi_install.ExcludeFromAll) {
- *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT";
- }
- *bmi_install_script << ")\n";
- *bmi_install_script << " file(INSTALL\n"
- " DESTINATION \"";
- if (!bmi_dest_is_abs) {
- *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/";
- }
- *bmi_install_script << cmEscape(bmi_install.Destination)
- << "\"\n"
- " TYPE FILE\n";
- if (bmi_install.Optional) {
- *bmi_install_script << " OPTIONAL\n";
- }
- if (!bmi_install.MessageLevel.empty()) {
- *bmi_install_script << " " << bmi_install.MessageLevel << "\n";
- }
- if (!bmi_install.Permissions.empty()) {
- *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions
- << "\n";
- }
- *bmi_install_script << " FILES \"" << m->second << "\")\n";
- if (bmi_dest_is_abs) {
- *bmi_install_script
- << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
- " \""
- << cmEscape(cmSystemTools::GetFilenameName(m->second))
- << "\")\n"
- " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
- " message(WARNING\n"
- " \"ABSOLUTE path INSTALL DESTINATION : "
- "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
- " endif ()\n"
- " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
- " message(FATAL_ERROR\n"
- " \"ABSOLUTE path INSTALL DESTINATION forbidden (by "
- "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n"
- " endif ()\n";
- }
- *bmi_install_script << "endif ()\n";
- }
- }
- }
-
- // Add trailing parenthesis for the `set_property` call.
- for (auto const& exp : exports) {
- *exp.first << ")\n";
- }
-
- // Check that public sources only require public modules.
- for (auto const& pub_reqs : public_source_requires) {
- for (auto const& req : pub_reqs.second) {
- if (private_modules.count(req)) {
- cmSystemTools::Error(cmStrCat(
- "Public C++ module source `", pub_reqs.first, "` requires the `",
- req, "` C++ module which is provided by a private source"));
- result = false;
- }
- }
- }
- }
-
- return result;
+ return cmDyndepCollation::WriteDyndepMetadata(arg_lang, objects, export_info,
+ cb);
}
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
@@ -3103,58 +2828,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
}
}
- cmGlobalNinjaGenerator::CxxModuleExportInfo export_info;
- export_info.Config = tdi["config"].asString();
- if (export_info.Config.empty()) {
- export_info.Config = "noconfig";
- }
- Json::Value const& tdi_exports = tdi["exports"];
- if (tdi_exports.isArray()) {
- for (auto const& tdi_export : tdi_exports) {
- CxxModuleExport exp;
- exp.Install = tdi_export["install"].asBool();
- exp.Name = tdi_export["export-name"].asString();
- exp.Destination = tdi_export["destination"].asString();
- exp.Prefix = tdi_export["export-prefix"].asString();
- exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString();
- exp.Namespace = tdi_export["namespace"].asString();
-
- export_info.Exports.push_back(exp);
- }
- }
- auto const& bmi_installation = tdi["bmi-installation"];
- if (bmi_installation.isObject()) {
- CxxModuleBmiInstall bmi_install;
-
- bmi_install.Component = bmi_installation["component"].asString();
- bmi_install.Destination = bmi_installation["destination"].asString();
- bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool();
- bmi_install.Optional = bmi_installation["optional"].asBool();
- bmi_install.Permissions = bmi_installation["permissions"].asString();
- bmi_install.MessageLevel = bmi_installation["message-level"].asString();
- bmi_install.ScriptLocation =
- bmi_installation["script-location"].asString();
-
- export_info.BmiInstallation = bmi_install;
- }
- Json::Value const& tdi_cxx_modules = tdi["cxx-modules"];
- if (tdi_cxx_modules.isObject()) {
- for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) {
- CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()];
- auto const& tdi_cxx_module_info = *i;
- fsi.Name = tdi_cxx_module_info["name"].asString();
- fsi.RelativeDirectory =
- tdi_cxx_module_info["relative-directory"].asString();
- fsi.SourcePath = tdi_cxx_module_info["source"].asString();
- fsi.Type = tdi_cxx_module_info["type"].asString();
- fsi.Visibility = cmFileSetVisibilityFromName(
- tdi_cxx_module_info["visibility"].asString(), nullptr);
- auto const& tdi_fs_dest = tdi_cxx_module_info["destination"];
- if (tdi_fs_dest.isString()) {
- fsi.Destination = tdi_fs_dest.asString();
- }
- }
- }
+ auto export_info = cmDyndepCollation::ParseExportInfo(tdi);
cmake cm(cmake::RoleInternal, cmState::Unknown);
cm.SetHomeDirectory(dir_top_src);
@@ -3164,7 +2838,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
!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,
- export_info)) {
+ *export_info)) {
return 1;
}
return 0;
@@ -3212,10 +2886,10 @@ cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm)
cm->GetState()->SetNinjaMulti(true);
}
-void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalNinjaMultiGenerator::GetDocumentation()
{
- entry.Name = cmGlobalNinjaMultiGenerator::GetActualName();
- entry.Brief = "Generates build-<Config>.ninja files.";
+ return { cmGlobalNinjaMultiGenerator::GetActualName(),
+ "Generates build-<Config>.ninja files." };
}
std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir(
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index f89e611..1436c83 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -35,7 +35,7 @@ class cmMakefile;
class cmOutputConverter;
class cmStateDirectory;
class cmake;
-struct cmDocumentationEntry;
+struct cmCxxModuleExportInfo;
/**
* \class cmGlobalNinjaGenerator
@@ -193,7 +193,7 @@ public:
/** Get encoding used by generator for ninja files */
codecvt::Encoding GetMakefileEncoding() const override;
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile* mf, bool optional) override;
@@ -292,7 +292,8 @@ public:
}
void AddCXXCompileCommand(const std::string& commandLine,
- const std::string& sourceFile);
+ const std::string& sourceFile,
+ const std::string& objPath);
/**
* Add a rule to the generated build system.
@@ -353,11 +354,6 @@ public:
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,
@@ -418,7 +414,6 @@ public:
bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
- struct CxxModuleExportInfo;
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,
@@ -426,7 +421,7 @@ public:
std::string const& module_dir,
std::vector<std::string> const& linked_target_dirs,
std::string const& arg_lang, std::string const& arg_modmapfmt,
- CxxModuleExportInfo const& export_info);
+ cmCxxModuleExportInfo const& export_info);
virtual std::string BuildAlias(const std::string& alias,
const std::string& /*config*/) const
@@ -470,7 +465,7 @@ public:
bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
- bool CheckCxxModuleSupport();
+ bool CheckCxxModuleSupport() override;
protected:
void Generate() override;
@@ -594,7 +589,7 @@ private:
codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
- bool DiagnosedCxxModuleSupport = false;
+ bool DiagnosedCxxModuleNinjaSupport = false;
void InitOutputPathPrefix();
@@ -617,7 +612,8 @@ private:
bool GenexOutput;
};
- std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures;
+ std::map<TargetDependsClosureKey, cmNinjaDeps>
+ TargetDependsClosureLocalOutputs;
TargetAliasMap TargetAliases;
@@ -657,7 +653,7 @@ public:
new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>());
}
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
std::string GetName() const override
{
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 21aa89c..30206b5 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -11,7 +11,6 @@
#include <cmext/algorithm>
#include <cmext/memory>
-#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -71,11 +70,10 @@ cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf)
cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf));
}
-void cmGlobalUnixMakefileGenerator3::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalUnixMakefileGenerator3::GetDocumentation()
{
- entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
- entry.Brief = "Generates standard UNIX makefiles.";
+ return { cmGlobalUnixMakefileGenerator3::GetActualName(),
+ "Generates standard UNIX makefiles." };
}
void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
@@ -104,6 +102,9 @@ void cmGlobalUnixMakefileGenerator3::Configure()
void cmGlobalUnixMakefileGenerator3::Generate()
{
+ this->ClangTidyExportFixesDirs.clear();
+ this->ClangTidyExportFixesFiles.clear();
+
// first do superclass method
this->cmGlobalGenerator::Generate();
@@ -139,11 +140,13 @@ void cmGlobalUnixMakefileGenerator3::Generate()
*this->CommandDatabase << "\n]";
this->CommandDatabase.reset();
}
+
+ this->RemoveUnknownClangTidyExportFixesFiles();
}
void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
const std::string& sourceFile, const std::string& workingDirectory,
- const std::string& compileCommand)
+ const std::string& compileCommand, const std::string& objPath)
{
if (!this->CommandDatabase) {
std::string commandDatabaseName =
@@ -164,7 +167,9 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
<< "\",\n"
<< R"( "file": ")"
<< cmGlobalGenerator::EscapeJSON(sourceFile)
- << "\"\n}";
+ << "\",\n"
+ << R"( "output": ")"
+ << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n}";
}
void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index b9d333e..214ba2a 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -24,7 +24,6 @@ class cmLocalUnixMakefileGenerator3;
class cmMakefile;
class cmMakefileTargetGenerator;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalUnixMakefileGenerator3
* \brief Write a Unix makefiles.
@@ -101,7 +100,7 @@ public:
bool SupportsCustomCommandDepfile() const override { return true; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
cmMakefile* mf) override;
@@ -174,7 +173,8 @@ public:
void AddCXXCompileCommand(const std::string& sourceFile,
const std::string& workingDirectory,
- const std::string& compileCommand);
+ const std::string& compileCommand,
+ const std::string& objPath);
/** Does the make tool tolerate .NOTPARALLEL? */
virtual bool AllowNotParallel() const { return true; }
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index bea2ae7..1e01dd6 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -56,6 +56,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator(
{
this->DefaultCudaFlagTableName = "v10";
this->DefaultCudaHostFlagTableName = "v10";
+ this->DefaultMarmasmFlagTableName = "v10";
this->DefaultNasmFlagTableName = "v10";
}
@@ -301,7 +302,7 @@ 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();
+ auto fi = fields.begin();
if (fi == fields.end()) {
return true;
}
@@ -500,7 +501,8 @@ bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf)
bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf)
{
- std::string v = this->GetInstalledNsightTegraVersion();
+ std::string v =
+ cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion();
if (v.empty()) {
mf->IssueMessage(MessageType::FATAL_ERROR,
"CMAKE_SYSTEM_NAME is 'Android' but "
@@ -771,10 +773,10 @@ std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand()
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,
+ mskey =
+ cmStrCat(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\)",
+ this->GetToolsVersion(), ";MSBuildToolsPath");
+ if (cmSystemTools::ReadRegistryValue(mskey, msbuild,
cmSystemTools::KeyWOW64_32)) {
cmSystemTools::ConvertToUnixSlashes(msbuild);
msbuild += "/MSBuild.exe";
@@ -797,6 +799,7 @@ std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand()
}
// Skip over the cmGlobalVisualStudio8Generator implementation because
// we expect a real devenv and do not want to look for VCExpress.
+ // NOLINTNEXTLINE(bugprone-parent-virtual-call)
return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand();
}
@@ -1107,8 +1110,9 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
// Decide if a restore is performed, based on a cache variable.
if (cmValue cached =
this->CMakeInstance->GetState()->GetCacheEntryValue(
- "CMAKE_VS_NUGET_PACKAGE_RESTORE"))
+ "CMAKE_VS_NUGET_PACKAGE_RESTORE")) {
restorePackages = cached.IsOn();
+ }
}
if (restorePackages) {
@@ -1136,7 +1140,7 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
std::string extension =
cmSystemTools::GetFilenameLastExtension(proj->GetRelativePath());
extension = cmSystemTools::LowerCase(extension);
- if (extension.compare(".csproj") == 0) {
+ if (extension == ".csproj") {
// Use correct platform name
platform =
slnData.GetConfigurationTarget(tname, plainConfig, platform);
@@ -1154,8 +1158,6 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
} else {
makeCommand.Add(cmStrCat("/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
@@ -1466,6 +1468,13 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
"CudaHost");
}
+cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMarmasmFlagTable()
+ const
+{
+ return LoadFlagTable(std::string(), this->DefaultMarmasmFlagTableName,
+ "MARMASM");
+}
+
cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
{
return LoadFlagTable(this->GetMasmFlagTableName(),
@@ -1489,6 +1498,17 @@ bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const
cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5));
}
+bool cmGlobalVisualStudio10Generator::IsBuildInParallelSupported() const
+{
+ if (this->Version >= VSVersion::VS16) {
+ return true;
+ }
+
+ static std::string const vsVer15_8_0 = "15.8.27705.0";
+ cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
+ return (vsVer &&
+ cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_8_0));
+}
std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
{
std::string const& toolset = this->GetPlatformToolsetString();
@@ -1496,19 +1516,23 @@ std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
if (toolset == "v142") {
return "v142";
- } else if (toolset == "v141") {
+ }
+ if (toolset == "v141") {
return "v141";
- } else if (useToolset == "v140") {
+ }
+ if (useToolset == "v140") {
return "v140";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
@@ -1518,19 +1542,23 @@ std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
if (useToolset == "v142") {
return "v142";
- } else if (useToolset == "v141") {
+ }
+ if (useToolset == "v141") {
return "v141";
- } else if (useToolset == "v140") {
+ }
+ if (useToolset == "v140") {
return "v140";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
@@ -1541,15 +1569,17 @@ std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
@@ -1560,15 +1590,17 @@ std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
@@ -1578,19 +1610,23 @@ std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
if (useToolset == "v142") {
return "v142";
- } else if (useToolset == "v141") {
+ }
+ if (useToolset == "v141") {
return "v141";
- } else if (useToolset == "v140") {
+ }
+ if (useToolset == "v140") {
return "v140";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
@@ -1601,15 +1637,17 @@ std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
if ((useToolset == "v140") || (useToolset == "v141") ||
(useToolset == "v142")) {
return "v14";
- } else if (useToolset == "v120") {
+ }
+ if (useToolset == "v120") {
return "v12";
- } else if (useToolset == "v110") {
+ }
+ if (useToolset == "v110") {
return "v11";
- } else if (useToolset == "v100") {
+ }
+ if (useToolset == "v100") {
return "v10";
- } else {
- return "";
}
+ return "";
}
std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index b32c0a7..deed206 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -163,10 +163,12 @@ public:
cmIDEFlagTable const* GetLinkFlagTable() const;
cmIDEFlagTable const* GetCudaFlagTable() const;
cmIDEFlagTable const* GetCudaHostFlagTable() const;
+ cmIDEFlagTable const* GetMarmasmFlagTable() const;
cmIDEFlagTable const* GetMasmFlagTable() const;
cmIDEFlagTable const* GetNasmFlagTable() const;
bool IsMsBuildRestoreSupported() const;
+ bool IsBuildInParallelSupported() const;
protected:
cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
@@ -226,6 +228,7 @@ protected:
std::string DefaultLinkFlagTableName;
std::string DefaultCudaFlagTableName;
std::string DefaultCudaHostFlagTableName;
+ std::string DefaultMarmasmFlagTableName;
std::string DefaultMasmFlagTableName;
std::string DefaultNasmFlagTableName;
std::string DefaultRCFlagTableName;
@@ -239,15 +242,10 @@ protected:
private:
struct LongestSourcePath
{
- LongestSourcePath()
- : Length(0)
- , Target(0)
- , SourceFile(0)
- {
- }
- size_t Length;
- cmGeneratorTarget* Target;
- cmSourceFile const* SourceFile;
+ LongestSourcePath() = default;
+ size_t Length = 0;
+ cmGeneratorTarget* Target = nullptr;
+ cmSourceFile const* SourceFile = nullptr;
std::string SourceRel;
};
LongestSourcePath LongestSource;
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 086d3af..3ad10eb 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -7,7 +7,6 @@
#include <utility>
#include <vector>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalVisualStudioGenerator.h"
@@ -23,7 +22,7 @@ static const char* cmVS11GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs11generatorName,
sizeof(vs11generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs11generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2012")) {
@@ -74,11 +73,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs11generatorName) + " [arch]";
- entry.Brief = "Deprecated. Generates Visual Studio 2012 project files. "
- "Optional [arch] can be \"Win64\" or \"ARM\".";
+ return { std::string(vs11generatorName) + " [arch]",
+ "Deprecated. Generates Visual Studio 2012 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\"." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -161,6 +160,18 @@ bool cmGlobalVisualStudio11Generator::MatchesGeneratorName(
return false;
}
+void cmGlobalVisualStudio11Generator::EnableLanguage(
+ std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
+{
+ for (std::string const& it : lang) {
+ if (it == "ASM_MARMASM") {
+ this->MarmasmEnabled = true;
+ }
+ }
+ this->AddPlatformDefinitions(mf);
+ cmGlobalVisualStudio10Generator::EnableLanguage(lang, mf, optional);
+}
+
bool cmGlobalVisualStudio11Generator::InitializeWindowsPhone(cmMakefile* mf)
{
if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) {
@@ -205,9 +216,8 @@ bool cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v110_wp80";
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
toolset);
@@ -221,9 +231,8 @@ bool cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v110";
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset(
toolset);
@@ -234,6 +243,7 @@ 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.
+ // NOLINTNEXTLINE(bugprone-parent-virtual-call)
return cmGlobalGenerator::UseFolderProperty();
}
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index 2f8a7f6..fd25984 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -25,6 +25,9 @@ public:
bool MatchesGeneratorName(const std::string& name) const override;
+ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
+ bool optional) override;
+
bool SupportsCustomCommandDepfile() const override { return true; }
cm::optional<cmDepfileFormat> DepfileFormat() const override
diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx
index 600ee0a..d417f9e 100644
--- a/Source/cmGlobalVisualStudio12Generator.cxx
+++ b/Source/cmGlobalVisualStudio12Generator.cxx
@@ -6,7 +6,6 @@
#include <sstream>
#include <vector>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalVisualStudioGenerator.h"
@@ -22,7 +21,7 @@ static const char* cmVS12GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs12generatorName,
sizeof(vs12generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs12generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2013")) {
@@ -62,11 +61,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>();
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs12generatorName) + " [arch]";
- entry.Brief = "Generates Visual Studio 2013 project files. "
- "Optional [arch] can be \"Win64\" or \"ARM\".";
+ return { std::string(vs12generatorName) + " [arch]",
+ "Generates Visual Studio 2013 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\"." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -195,9 +194,8 @@ bool cmGlobalVisualStudio12Generator::SelectWindowsPhoneToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v120_wp81";
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset(
toolset);
@@ -211,9 +209,8 @@ bool cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v120";
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
toolset);
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 9f94cca..7424ca3 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -7,7 +7,6 @@
#include <cm/vector>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalVisualStudioGenerator.h"
@@ -24,7 +23,7 @@ static const char* cmVS14GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs14generatorName,
sizeof(vs14generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs14generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2015")) {
@@ -64,11 +63,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>();
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs14generatorName) + " [arch]";
- entry.Brief = "Generates Visual Studio 2015 project files. "
- "Optional [arch] can be \"Win64\" or \"ARM\".";
+ return { std::string(vs14generatorName) + " [arch]",
+ "Generates Visual Studio 2015 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\"." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -214,9 +213,8 @@ bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = "v140";
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
toolset);
@@ -256,7 +254,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion(
return std::string();
}
// If the value is something else, trust that it is a valid SDK value.
- else if (value) {
+ if (value) {
return *value;
}
// If value is an invalid pointer, leave result unchanged.
@@ -374,6 +372,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
return sdks.at(0);
}
#endif
+ (void)mf;
// Return an empty string
return std::string();
}
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index 758ce83..de13924 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -101,14 +101,14 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
// check to see if this is a fortran build
std::string ext = ".vcproj";
const char* project =
- "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"";
+ R"(Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = ")";
if (this->TargetIsFortranOnly(t)) {
ext = ".vfproj";
- project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \"";
+ project = R"(Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = ")";
}
if (t->IsCSharpOnly()) {
ext = ".csproj";
- project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"";
+ project = R"(Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = ")";
}
cmValue targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT");
if (targetExt) {
@@ -125,11 +125,11 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout,
fout << "EndProject\n";
- UtilityDependsMap::iterator ui = this->UtilityDepends.find(t);
+ auto 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}\") = \""
+ fout << R"(Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = ")"
<< uname << "\", \""
<< this->ConvertToSolutionPath(dir) << (dir[0]? "\\":"")
<< uname << ".vcproj" << "\", \"{"
@@ -168,8 +168,10 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject(
cmValue typeGuid, const std::set<BT<std::pair<std::string, bool>>>& depends)
{
fout << "Project(\"{"
- << (typeGuid ? typeGuid
- : std::string(this->ExternalProjectType(location)))
+ << (typeGuid ? *typeGuid
+ : std::string(
+ cmGlobalVisualStudio71Generator::ExternalProjectType(
+ location)))
<< "}\") = \"" << name << "\", \""
<< this->ConvertToSolutionPath(location) << "\", \"{"
<< this->GetGUID(name) << "}\"\n";
@@ -216,8 +218,7 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations(
}
fout << "\t\t{" << guid << "}." << i << ".ActiveCfg = " << dstConfig << "|"
<< platformName << std::endl;
- std::set<std::string>::const_iterator ci =
- configsPartOfDefaultBuild.find(i);
+ auto ci = configsPartOfDefaultBuild.find(i);
if (!(ci == configsPartOfDefaultBuild.end())) {
fout << "\t\t{" << guid << "}." << i << ".Build.0 = " << dstConfig << "|"
<< platformName << std::endl;
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index ff76762..d483135 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -70,14 +70,13 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator(
: cmGlobalVisualStudioGenerator(cm, platformInGeneratorName)
{
this->DevEnvCommandInitialized = false;
+ this->MarmasmEnabled = false;
this->MasmEnabled = false;
this->NasmEnabled = false;
this->ExtraFlagTable = cmVS7ExtraFlagTable;
}
-cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator()
-{
-}
+cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator() = default;
// Package GUID of Intel Visual Fortran plugin to VS IDE
#define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}"
@@ -159,7 +158,7 @@ std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand()
// Search in standard location.
vskey = this->GetRegistryBase() + ";InstallDir";
- if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd,
+ if (cmSystemTools::ReadRegistryValue(vskey, vscmd,
cmSystemTools::KeyWOW64_32)) {
cmSystemTools::ConvertToUnixSlashes(vscmd);
vscmd += "/devenv.com";
@@ -169,10 +168,10 @@ std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand()
}
// Search where VS15Preview places it.
- vskey = cmStrCat(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;",
- this->GetIDEVersion());
- if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd,
+ vskey =
+ cmStrCat(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7;)",
+ this->GetIDEVersion());
+ if (cmSystemTools::ReadRegistryValue(vskey, vscmd,
cmSystemTools::KeyWOW64_32)) {
cmSystemTools::ConvertToUnixSlashes(vscmd);
vscmd += "/Common7/IDE/devenv.com";
@@ -191,17 +190,23 @@ const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
std::string extension = cmSystemTools::GetFilenameLastExtension(location);
if (extension == ".vbproj") {
return "F184B08F-C81C-45F6-A57F-5ABD9991F28F";
- } else if (extension == ".csproj") {
+ }
+ if (extension == ".csproj") {
return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
- } else if (extension == ".fsproj") {
+ }
+ if (extension == ".fsproj") {
return "F2A71F9B-5D33-465A-A702-920D77279786";
- } else if (extension == ".vdproj") {
+ }
+ if (extension == ".vdproj") {
return "54435603-DBB4-11D2-8724-00A0C9A8B90C";
- } else if (extension == ".dbproj") {
+ }
+ if (extension == ".dbproj") {
return "C8D11400-126E-41CD-887F-60BD40844F9E";
- } else if (extension == ".wixproj") {
+ }
+ if (extension == ".wixproj") {
return "930C7802-8A8C-48F9-8165-68863BCCD9DD";
- } else if (extension == ".pyproj") {
+ }
+ if (extension == ".pyproj") {
return "888888A0-9F3D-457C-B088-3A5042F75D52";
}
return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
@@ -333,7 +338,7 @@ void cmGlobalVisualStudio7Generator::OutputSLNFile(
}
this->CurrentProject = root->GetProjectName();
std::string fname = GetSLNFile(root);
- cmGeneratedFileStream fout(fname.c_str());
+ cmGeneratedFileStream fout(fname);
fout.SetCopyIfDifferent(true);
if (!fout) {
return;
@@ -379,7 +384,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations(
// On VS 19 and above, always map .NET SDK projects to "Any CPU".
if (target->IsDotNetSdkTarget() &&
this->GetVersion() >= VSVersion::VS16 &&
- !this->IsReservedTarget(target->GetName())) {
+ !cmGlobalVisualStudio7Generator::IsReservedTarget(
+ target->GetName())) {
mapping = "Any CPU";
}
this->WriteProjectConfigurations(fout, *vcprojName, *target, configs,
@@ -420,7 +426,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
if (expath) {
std::string project = target->GetName();
- std::string location = *expath;
+ std::string const& location = *expath;
this->WriteExternalProject(fout, project, location,
target->GetProperty("VS_PROJECT_TYPE"),
@@ -451,7 +457,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution(
std::string cumulativePath;
for (std::string const& iter : tokens) {
- if (!iter.size()) {
+ if (iter.empty()) {
continue;
}
@@ -500,7 +506,7 @@ void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout)
std::string guidParent(this->GetGUID(key));
for (std::string const& it : iter.second) {
- std::string value(it);
+ std::string const& value(it);
std::string guid(this->GetGUID(value));
fout << "\t\t{" << guid << "} = {" << guidParent << "}\n";
@@ -516,7 +522,7 @@ std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath(
// use windows slashes.
std::string d = path;
std::string::size_type pos = 0;
- while ((pos = d.find('/', pos)) != d.npos) {
+ while ((pos = d.find('/', pos)) != std::string::npos) {
d[pos++] = '\\';
}
return d;
@@ -540,8 +546,9 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
} else if (cmHasLiteralPrefix(name, "POST_")) {
name = name.substr(5);
sectionType = "postSolution";
- } else
+ } else {
continue;
+ }
if (!name.empty()) {
bool addGuid = false;
if (name == "ExtensibilityGlobals" && sectionType == "postSolution") {
@@ -579,9 +586,10 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections(
<< "\t\tSolutionGuid = {" << guid << "}\n"
<< "\tEndGlobalSection\n";
}
- if (!extensibilityAddInsOverridden)
+ if (!extensibilityAddInsOverridden) {
fout << "\tGlobalSection(ExtensibilityAddIns) = postSolution\n"
<< "\tEndGlobalSection\n";
+ }
}
// Standard end of dsw file
@@ -600,13 +608,13 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend(
std::string fname =
cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
pname, ".vcproj");
- cmGeneratedFileStream fout(fname.c_str());
+ cmGeneratedFileStream fout(fname);
fout.SetCopyIfDifferent(true);
- std::string guid = this->GetGUID(pname.c_str());
+ std::string guid = this->GetGUID(pname);
/* clang-format off */
fout <<
- "<?xml version=\"1.0\" encoding = \""
+ R"(<?xml version="1.0" encoding = ")"
<< this->Encoding() << "\"?>\n"
"<VisualStudioProject\n"
"\tProjectType=\"Visual C++\"\n"
@@ -729,13 +737,12 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild(
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;
+ return std::any_of(projectTargets.begin(), projectTargets.end(),
+ [this, gtIn](cmTargetDepend const& l) {
+ TargetDependSet const& tgtdeps =
+ this->GetTargetDirectDepends(l);
+ return tgtdeps.count(gtIn);
+ });
}
std::string cmGlobalVisualStudio7Generator::Encoding()
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 288069c..6f6109e 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -31,7 +31,7 @@ class BT;
class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator
{
public:
- ~cmGlobalVisualStudio7Generator();
+ ~cmGlobalVisualStudio7Generator() override;
//! Create a local generator appropriate to this Global Generator
std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
@@ -106,6 +106,7 @@ public:
bool FindMakeProgram(cmMakefile* mf) override;
/** Is the Microsoft Assembler enabled? */
+ bool IsMarmasmEnabled() const { return this->MarmasmEnabled; }
bool IsMasmEnabled() const { return this->MasmEnabled; }
bool IsNasmEnabled() const { return this->NasmEnabled; }
@@ -114,6 +115,8 @@ public:
cmIDEFlagTable const* ExtraFlagTable;
+ virtual bool SupportsCxxModuleDyndep() const { return false; }
+
protected:
cmGlobalVisualStudio7Generator(cmake* cm,
std::string const& platformInGeneratorName);
@@ -157,8 +160,6 @@ protected:
cmValue typeGuid,
const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
- virtual bool SupportsCxxModuleDyndep() const { return false; }
-
std::string ConvertToSolutionPath(const std::string& path);
std::set<std::string> IsPartOfDefaultBuild(
@@ -176,6 +177,7 @@ protected:
// Set during OutputSLNFile with the name of the current project.
// There is one SLN file per project.
std::string CurrentProject;
+ bool MarmasmEnabled;
bool MasmEnabled;
bool NasmEnabled;
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 323ee67..647fc2d 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -44,7 +44,8 @@ cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator(
{
this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms";
this->Name = name;
- this->ExtraFlagTable = this->GetExtraFlagTableVS8();
+ this->ExtraFlagTable =
+ cmGlobalVisualStudio8Generator::GetExtraFlagTableVS8();
}
std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand()
@@ -52,9 +53,9 @@ std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand()
// First look for VCExpress.
std::string vsxcmd;
std::string vsxkey =
- cmStrCat("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\",
+ cmStrCat(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VCExpress\)",
this->GetIDEVersion(), ";InstallDir");
- if (cmSystemTools::ReadRegistryValue(vsxkey.c_str(), vsxcmd,
+ if (cmSystemTools::ReadRegistryValue(vsxkey, vsxcmd,
cmSystemTools::KeyWOW64_32)) {
cmSystemTools::ConvertToUnixSlashes(vsxcmd);
vsxcmd += "/VCExpress.exe";
@@ -149,6 +150,7 @@ void cmGlobalVisualStudio8Generator::Configure()
bool cmGlobalVisualStudio8Generator::UseFolderProperty() const
{
+ // NOLINTNEXTLINE(bugprone-parent-virtual-call)
return IsExpressEdition() ? false : cmGlobalGenerator::UseFolderProperty();
}
@@ -172,7 +174,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
std::move(cc));
auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
- auto gt = ptr.get();
+ auto* gt = ptr.get();
lg.AddGeneratorTarget(std::move(ptr));
// Organize in the "predefined targets" folder:
@@ -190,7 +192,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
cmStrCat(generators[0]->GetMakefile()->GetCurrentBinaryDirectory(), '/',
stampList);
std::string stampFile;
- cmGeneratedFileStream fout(stampListFile.c_str());
+ cmGeneratedFileStream fout(stampListFile);
for (const auto& gi : generators) {
stampFile = cmStrCat(gi->GetMakefile()->GetCurrentBinaryDirectory(),
"/CMakeFiles/generate.stamp");
@@ -237,8 +239,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget()
// 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());
+ auto new_end = std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(new_end, listFiles.end());
// Create a rule to re-run CMake.
@@ -277,8 +278,8 @@ 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();
+ for (auto& LocalGenerator : this->LocalGenerators) {
+ const auto& tgts = LocalGenerator->GetGeneratorTargets();
// All targets depend on the build-system check target.
for (const auto& ti : tgts) {
if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
@@ -324,8 +325,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations(
<< (!platformMapping.empty() ? platformMapping
: this->GetPlatformName())
<< "\n";
- std::set<std::string>::const_iterator ci =
- configsPartOfDefaultBuild.find(i);
+ auto ci = configsPartOfDefaultBuild.find(i);
if (!(ci == configsPartOfDefaultBuild.end())) {
fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName()
<< ".Build.0 = " << dstConfig << "|"
@@ -382,6 +382,7 @@ bool cmGlobalVisualStudio8Generator::ComputeTargetDepends()
{
// Skip over the cmGlobalVisualStudioGenerator implementation!
// We do not need the support that VS <= 7.1 needs.
+ // NOLINTNEXTLINE(bugprone-parent-virtual-call)
return this->cmGlobalGenerator::ComputeTargetDepends();
}
@@ -404,20 +405,23 @@ 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;
+ auto const& utilities = target->GetUtilities();
+ return std::any_of(
+ utilities.begin(), utilities.end(),
+ [target](BT<std::pair<std::string, bool>> const& ui) {
+ 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;
+ return false;
+ });
}
static cmVS7FlagTable cmVS8ExtraFlagTable[] = {
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
index e03e665..9f6550b 100644
--- a/Source/cmGlobalVisualStudio9Generator.cxx
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -6,7 +6,6 @@
#include <utility>
#include <vector>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalVisualStudioGenerator.h"
@@ -62,11 +61,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs9generatorName) + " [arch]";
- entry.Brief = "Generates Visual Studio 2008 project files. "
- "Optional [arch] can be \"Win64\" or \"IA64\".";
+ return { std::string(vs9generatorName) + " [arch]",
+ "Generates Visual Studio 2008 project files. "
+ "Optional [arch] can be \"Win64\" or \"IA64\"." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -159,5 +158,5 @@ std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory()
std::string cmGlobalVisualStudio9Generator::GetUserMacrosRegKeyBase()
{
- return "Software\\Microsoft\\VisualStudio\\9.0\\vsmacros";
+ return R"(Software\Microsoft\VisualStudio\9.0\vsmacros)";
}
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 9d168d0..31f6f77 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -51,9 +51,7 @@ cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator(
}
}
-cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator()
-{
-}
+cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator() = default;
cmGlobalVisualStudioGenerator::VSVersion
cmGlobalVisualStudioGenerator::GetVersion() const
@@ -188,7 +186,7 @@ std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
std::string cmGlobalVisualStudioGenerator::GetRegistryBase(const char* version)
{
- std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
+ std::string key = R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\)";
return key + version;
}
@@ -520,13 +518,12 @@ std::string cmGlobalVisualStudioGenerator::GetStartupProjectName(
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.");
}
+ root->GetMakefile()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "Directory property VS_STARTUP_PROJECT specifies target "
+ "'" +
+ startup + "' that does not exist. Ignoring.");
}
// default, if not specified
@@ -961,7 +958,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
commands.push_back(std::move(command));
}
-static bool OpenSolution(std::string sln)
+static bool OpenSolution(std::string const& sln)
{
HRESULT comInitialized =
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 576e4f2..3e20ada 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -44,7 +44,7 @@ public:
VS17 = 170
};
- virtual ~cmGlobalVisualStudioGenerator();
+ ~cmGlobalVisualStudioGenerator() override;
VSVersion GetVersion() const;
void SetVersion(VSVersion v);
@@ -133,8 +133,8 @@ public:
std::string First;
public:
- TargetCompare(std::string const& first)
- : First(first)
+ TargetCompare(std::string first)
+ : First(std::move(first))
{
}
bool operator()(cmGeneratorTarget const* l,
@@ -193,7 +193,6 @@ protected:
using UtilityDependsMap = std::map<cmGeneratorTarget const*, std::string>;
UtilityDependsMap UtilityDepends;
-protected:
VSVersion Version;
bool ExpressEdition;
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index be318c1..415eb7c 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -14,7 +14,6 @@
#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmMakefile.h"
@@ -54,7 +53,8 @@ static bool VSIsArm64Host()
# undef CM_VS_GCC_DIAGNOSTIC_PUSHED
#endif
- USHORT processMachine, nativeMachine;
+ USHORT processMachine;
+ USHORT nativeMachine;
return s_IsWow64Process2Impl != nullptr &&
s_IsWow64Process2Impl(GetCurrentProcess(), &processMachine,
@@ -66,7 +66,7 @@ static bool VSHasDotNETFrameworkArm64()
{
std::string dotNetArm64;
return cmSystemTools::ReadRegistryValue(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\.NETFramework;InstallRootArm64",
+ R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework;InstallRootArm64)",
dotNetArm64, cmSystemTools::KeyWOW64_64);
}
@@ -86,19 +86,19 @@ static std::string VSHostPlatformName()
{
if (VSIsArm64Host()) {
return "ARM64";
- } else if (VSIsWow64()) {
+ }
+ if (VSIsWow64()) {
return "x64";
- } else {
+ }
#if defined(_M_ARM)
- return "ARM";
+ return "ARM";
#elif defined(_M_IA64)
- return "Itanium";
+ return "Itanium";
#elif defined(_WIN64)
- return "x64";
+ return "x64";
#else
- return "Win32";
+ return "Win32";
#endif
- }
}
static std::string VSHostArchitecture(
@@ -106,19 +106,19 @@ static std::string VSHostArchitecture(
{
if (VSIsArm64Host()) {
return v >= cmGlobalVisualStudioGenerator::VSVersion::VS17 ? "ARM64" : "";
- } else if (VSIsWow64()) {
+ }
+ if (VSIsWow64()) {
return "x64";
- } else {
+ }
#if defined(_M_ARM)
- return "";
+ return "";
#elif defined(_M_IA64)
- return "";
+ return "";
#elif defined(_WIN64)
- return "x64";
+ return "x64";
#else
- return "x86";
+ return "x86";
#endif
- }
}
static unsigned int VSVersionToMajor(
@@ -212,7 +212,7 @@ static const char* cmVS15GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs15generatorName,
sizeof(vs15generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs15generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2017")) {
@@ -255,11 +255,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>();
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs15generatorName) + " [arch]";
- entry.Brief = "Generates Visual Studio 2017 project files. "
- "Optional [arch] can be \"Win64\" or \"ARM\".";
+ return { std::string(vs15generatorName) + " [arch]",
+ "Generates Visual Studio 2017 project files. "
+ "Optional [arch] can be \"Win64\" or \"ARM\"." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -307,7 +307,7 @@ static const char* cmVS16GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs16generatorName,
sizeof(vs16generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs16generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2019")) {
@@ -321,7 +321,7 @@ static const char* cmVS17GenName(const std::string& name, std::string& genName)
{
if (strncmp(name.c_str(), vs17generatorName,
sizeof(vs17generatorName) - 6) != 0) {
- return 0;
+ return nullptr;
}
const char* p = name.c_str() + sizeof(vs17generatorName) - 6;
if (cmHasLiteralPrefix(p, " 2022")) {
@@ -351,11 +351,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>();
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs16generatorName);
- entry.Brief = "Generates Visual Studio 2019 project files. "
- "Use -A option to specify architecture.";
+ return { std::string(vs16generatorName),
+ "Generates Visual Studio 2019 project files. "
+ "Use -A option to specify architecture." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -416,11 +416,11 @@ public:
return std::unique_ptr<cmGlobalGenerator>();
}
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- entry.Name = std::string(vs17generatorName);
- entry.Brief = "Generates Visual Studio 2022 project files. "
- "Use -A option to specify architecture.";
+ return { std::string(vs17generatorName),
+ "Generates Visual Studio 2022 project files. "
+ "Use -A option to specify architecture." };
}
std::vector<std::string> GetGeneratorNames() const override
@@ -521,6 +521,7 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
{
if (this->LastGeneratorInstanceString &&
i == *(this->LastGeneratorInstanceString)) {
+ this->SetVSVersionVar(mf);
return true;
}
@@ -531,7 +532,7 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
if (!this->GeneratorInstanceVersion.empty()) {
std::string const majorStr = VSVersionToMajorString(this->Version);
cmsys::RegularExpression versionRegex(
- cmStrCat("^", majorStr, "\\.[0-9]+\\.[0-9]+\\.[0-9]+$"));
+ cmStrCat("^", majorStr, R"(\.[0-9]+\.[0-9]+\.[0-9]+$)"));
if (!versionRegex.find(this->GeneratorInstanceVersion)) {
std::ostringstream e;
/* clang-format off */
@@ -592,6 +593,8 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance(
cmStateEnums::INTERNAL);
}
+ this->SetVSVersionVar(mf);
+
// The selected instance may have a different MSBuild than previously found.
this->MSBuildCommandInitialized = false;
@@ -607,7 +610,7 @@ bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance(
this->GeneratorInstanceVersion.clear();
std::vector<std::string> const fields = cmTokenize(is, ",");
- std::vector<std::string>::const_iterator fi = fields.begin();
+ auto fi = fields.begin();
if (fi == fields.end()) {
return true;
}
@@ -672,6 +675,13 @@ bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance(
return true;
}
+void cmGlobalVisualStudioVersionedGenerator::SetVSVersionVar(cmMakefile* mf)
+{
+ if (cm::optional<std::string> vsVer = this->GetVSInstanceVersion()) {
+ mf->AddDefinition("CMAKE_VS_VERSION_BUILD_NUMBER", *vsVer);
+ }
+}
+
bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField(
std::string const& key, std::string const& value)
{
@@ -901,9 +911,8 @@ bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset(
this->IsWindowsDesktopToolsetInstalled()) {
toolset = VSVersionToToolset(this->Version);
return true;
- } else {
- return false;
}
+ return false;
}
return this->cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
toolset);
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
index 2e573ec..45aca74 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.h
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.h
@@ -46,6 +46,16 @@ public:
const char* GetAndroidApplicationTypeRevision() const override;
+ bool CheckCxxModuleSupport() override
+ {
+ this->CxxModuleSupportCheck();
+ return this->SupportsCxxModuleDyndep();
+ }
+ bool SupportsCxxModuleDyndep() const override
+ {
+ return this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17;
+ }
+
protected:
cmGlobalVisualStudioVersionedGenerator(
VSVersion version, cmake* cm, const std::string& name,
@@ -83,6 +93,7 @@ private:
mutable cmVSSetupAPIHelper vsSetupAPIHelper;
bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf);
+ void SetVSVersionVar(cmMakefile* mf);
std::string GeneratorInstance;
std::string GeneratorInstanceVersion;
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index fb2a8b6..ed44e6b 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -4,7 +4,6 @@
#include <ostream>
-#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmState.h"
@@ -54,11 +53,10 @@ bool cmGlobalWatcomWMakeGenerator::SetSystemName(std::string const& s,
return this->cmGlobalUnixMakefileGenerator3::SetSystemName(s, mf);
}
-void cmGlobalWatcomWMakeGenerator::GetDocumentation(
- cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalWatcomWMakeGenerator::GetDocumentation()
{
- entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName();
- entry.Brief = "Generates Watcom WMake makefiles.";
+ return { cmGlobalWatcomWMakeGenerator::GetActualName(),
+ "Generates Watcom WMake makefiles." };
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index eb93934..5579120 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -15,7 +15,6 @@
class cmMakefile;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalWatcomWMakeGenerator
* \brief Write a NMake makefiles.
@@ -39,7 +38,7 @@ public:
static std::string GetActualName() { return "Watcom WMake"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
/** Tell the generator about the target system. */
bool SetSystemName(std::string const& s, cmMakefile* mf) override;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 116e510..4746507 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -13,6 +13,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -24,7 +25,6 @@
#include "cmCustomCommandGenerator.h"
#include "cmCustomCommandLines.h"
#include "cmCustomCommandTypes.h"
-#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
@@ -149,9 +149,9 @@ public:
std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
const std::string& name, bool allowArch, cmake* cm) const override;
- void GetDocumentation(cmDocumentationEntry& entry) const override
+ cmDocumentationEntry GetDocumentation() const override
{
- cmGlobalXCodeGenerator::GetDocumentation(entry);
+ return cmGlobalXCodeGenerator::GetDocumentation();
}
std::vector<std::string> GetGeneratorNames() const override
@@ -2281,11 +2281,11 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
}
makefileStream << "\n";
- if (const char* comment = ccg.GetComment()) {
+ if (cm::optional<std::string> comment = ccg.GetComment()) {
std::string echo_cmd =
cmStrCat("echo ",
(this->CurrentLocalGenerator->EscapeForShell(
- comment, ccg.GetCC().GetEscapeAllowMakeVars())));
+ *comment, ccg.GetCC().GetEscapeAllowMakeVars())));
makefileStream << "\t" << echo_cmd << "\n";
}
@@ -2516,10 +2516,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
}
// Get the product name components.
- std::string pnprefix;
- std::string pnbase;
- std::string pnsuffix;
- gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
+ cmGeneratorTarget::NameComponents const& components =
+ gtgt->GetFullNameComponents(configName);
cmValue version = gtgt->GetProperty("VERSION");
cmValue soversion = gtgt->GetProperty("SOVERSION");
@@ -2534,8 +2532,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
version = soversion;
}
- std::string realName = pnbase;
- std::string soName = pnbase;
+ std::string realName = components.base;
+ std::string soName = components.base;
if (version && soversion) {
realName += ".";
realName += *version;
@@ -2565,15 +2563,15 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
gtgt->GetType() == cmStateEnums::SHARED_LIBRARY ||
gtgt->GetType() == cmStateEnums::MODULE_LIBRARY ||
gtgt->GetType() == cmStateEnums::EXECUTABLE) {
-
+ std::string prefix = components.prefix;
if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) {
- pnprefix = "";
+ prefix = "";
}
buildSettings->AddAttribute("EXECUTABLE_PREFIX",
- this->CreateString(pnprefix));
+ this->CreateString(prefix));
buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
- this->CreateString(pnsuffix));
+ this->CreateString(components.suffix));
}
// Store the product name for all target types.
@@ -2977,6 +2975,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
this->CreateString(extraLinkOptions));
buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString(""));
buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
+ buildSettings->AddAttribute("ALWAYS_SEARCH_USER_PATHS",
+ this->CreateString("NO"));
buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
group->AddObject(this->CreateString("$(inherited)"));
@@ -3623,7 +3623,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
}
// Add a pair of config and item to target-item map
auto& itemVector = targetItemMap[libName];
- itemVector.emplace_back(ConfigItemPair(configName, &libItem));
+ itemVector.emplace_back(configName, &libItem);
// Add product file-name to a lib-product map
auto productName =
cmSystemTools::GetFilenameName(libItem.Value.Value);
@@ -3962,7 +3962,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
void cmGlobalXCodeGenerator::AddEmbeddedObjects(
cmXCodeObject* target, const std::string& copyFilesBuildPhaseName,
const std::string& embedPropertyName, const std::string& dstSubfolderSpec,
- int actionsOnByDefault)
+ int actionsOnByDefault, const std::string& defaultDstPath)
{
cmGeneratorTarget* gt = target->GetTarget();
if (!gt) {
@@ -3998,7 +3998,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects(
copyFilesBuildPhase->AddAttribute("dstPath",
this->CreateString(*fwEmbedPath));
} else {
- copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString(""));
+ copyFilesBuildPhase->AddAttribute("dstPath",
+ this->CreateString(defaultDstPath));
}
copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
this->CreateString("0"));
@@ -4124,6 +4125,17 @@ void cmGlobalXCodeGenerator::AddEmbeddedAppExtensions(cmXCodeObject* target)
RemoveHeadersOnCopyByDefault);
}
+void cmGlobalXCodeGenerator::AddEmbeddedExtensionKitExtensions(
+ cmXCodeObject* target)
+{
+ static const auto dstSubfolderSpec = "16";
+
+ this->AddEmbeddedObjects(target, "Embed App Extensions",
+ "XCODE_EMBED_EXTENSIONKIT_EXTENSIONS",
+ dstSubfolderSpec, RemoveHeadersOnCopyByDefault,
+ "$(EXTENSIONS_FOLDER_PATH)");
+}
+
bool cmGlobalXCodeGenerator::CreateGroups(
std::vector<cmLocalGenerator*>& generators)
{
@@ -4369,7 +4381,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
cmXCodeObject* config =
this->CreateObject(cmXCodeObject::XCBuildConfiguration);
config->AddAttribute("name", this->CreateString(name));
- configs.push_back(std::make_pair(name, config));
+ configs.emplace_back(name, config);
}
if (defaultConfigName.empty()) {
defaultConfigName = "Debug";
@@ -4444,12 +4456,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
buildSettings->AddAttribute("CODE_SIGNING_ALLOWED",
this->CreateString("NO"));
}
+ auto debugConfigs = this->GetCMakeInstance()->GetDebugConfigs();
+ std::set<std::string> debugConfigSet(debugConfigs.begin(),
+ debugConfigs.end());
for (auto& config : configs) {
CreateGlobalXCConfigSettings(root, config.second, config.first);
cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
+ if (debugConfigSet.count(cmSystemTools::UpperCase(config.first)) == 0) {
+ buildSettingsForCfg->AddAttribute("SWIFT_COMPILATION_MODE",
+ this->CreateString("wholemodule"));
+ }
+
// Put this last so it can override existing settings
// Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
@@ -4507,6 +4527,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
this->AddEmbeddedFrameworks(t);
this->AddEmbeddedPlugIns(t);
this->AddEmbeddedAppExtensions(t);
+ this->AddEmbeddedExtensionKitExtensions(t);
// Inherit project-wide values for any target-specific search paths.
this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS");
this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS");
@@ -4517,6 +4538,9 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
this->InheritBuildSettingAttribute(t, "GCC_PREPROCESSOR_DEFINITIONS");
this->InheritBuildSettingAttribute(t, "OTHER_CFLAGS");
this->InheritBuildSettingAttribute(t, "OTHER_LDFLAGS");
+ this->InheritBuildSettingAttribute(t, "OTHER_SWIFT_FLAGS");
+ this->InheritBuildSettingAttribute(t,
+ "SWIFT_ACTIVE_COMPILATION_CONDITIONS");
}
if (this->XcodeBuildSystem == BuildSystem::One) {
@@ -4888,10 +4912,10 @@ std::string cmGlobalXCodeGenerator::ExpandCFGIntDir(
return tmp;
}
-void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
+cmDocumentationEntry cmGlobalXCodeGenerator::GetDocumentation()
{
- entry.Name = cmGlobalXCodeGenerator::GetActualName();
- entry.Brief = "Generate Xcode project files.";
+ return { cmGlobalXCodeGenerator::GetActualName(),
+ "Generate Xcode project files." };
}
std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
@@ -4974,7 +4998,13 @@ void cmGlobalXCodeGenerator::AppendDefines(
std::string def;
for (auto const& define : defines) {
// Start with -D if requested.
- def = cmStrCat(dflag ? "-D" : "", define);
+ if (dflag && !cmHasLiteralPrefix(define, "-D")) {
+ def = cmStrCat("-D", define);
+ } else if (!dflag && cmHasLiteralPrefix(define, "-D")) {
+ def = define.substr(2);
+ } else {
+ def = define;
+ }
// Append the flag with needed escapes.
std::string tmp;
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 9ae75fb..1fdd189 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -14,6 +14,7 @@
#include <cm/optional>
#include <cm/string_view>
+#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmTransformDepfile.h"
#include "cmValue.h"
@@ -28,7 +29,6 @@ class cmMakefile;
class cmSourceFile;
class cmSourceGroup;
class cmake;
-struct cmDocumentationEntry;
/** \class cmGlobalXCodeGenerator
* \brief Write a Unix makefiles.
@@ -54,7 +54,7 @@ public:
static std::string GetActualName() { return "Xcode"; }
/** Get the documentation entry for this generator. */
- static void GetDocumentation(cmDocumentationEntry& entry);
+ static cmDocumentationEntry GetDocumentation();
//! Create a local generator appropriate to this Global Generator
std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
@@ -218,10 +218,12 @@ private:
const std::string& copyFilesBuildPhaseName,
const std::string& embedPropertyName,
const std::string& dstSubfolderSpec,
- int actionsOnByDefault);
+ int actionsOnByDefault,
+ const std::string& defaultDstPath = "");
void AddEmbeddedFrameworks(cmXCodeObject* target);
void AddEmbeddedPlugIns(cmXCodeObject* target);
void AddEmbeddedAppExtensions(cmXCodeObject* target);
+ void AddEmbeddedExtensionKitExtensions(cmXCodeObject* target);
void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target,
cmXCodeObject* buildSettings,
const std::string& configName);
diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h
index fe9fbe2..01fc5f9 100644
--- a/Source/cmGraphAdjacencyList.h
+++ b/Source/cmGraphAdjacencyList.h
@@ -4,6 +4,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <cstddef>
#include <utility>
#include <vector>
@@ -17,14 +18,14 @@
class cmGraphEdge
{
public:
- cmGraphEdge(int n, bool s, bool c, cmListFileBacktrace bt)
+ cmGraphEdge(size_t n, bool s, bool c, cmListFileBacktrace bt)
: Dest(n)
, Strong(s)
, Cross(c)
, Backtrace(std::move(bt))
{
}
- operator int() const { return this->Dest; }
+ operator size_t() const { return this->Dest; }
bool IsStrong() const { return this->Strong; }
@@ -33,7 +34,7 @@ public:
cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; }
private:
- int Dest;
+ size_t Dest;
bool Strong;
bool Cross;
cmListFileBacktrace Backtrace;
@@ -41,7 +42,7 @@ private:
struct cmGraphEdgeList : public std::vector<cmGraphEdge>
{
};
-struct cmGraphNodeList : public std::vector<int>
+struct cmGraphNodeList : public std::vector<size_t>
{
};
struct cmGraphAdjacencyList : public std::vector<cmGraphEdgeList>
diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx
index c09aa46..9468d4a 100644
--- a/Source/cmIDEOptions.cxx
+++ b/Source/cmIDEOptions.cxx
@@ -20,15 +20,13 @@ cmIDEOptions::cmIDEOptions()
this->AllowDefine = true;
this->DoingInclude = false;
this->AllowSlash = false;
- this->DoingFollowing = 0;
- for (int i = 0; i < FlagTableCount; ++i) {
- this->FlagTable[i] = 0;
+ this->DoingFollowing = nullptr;
+ for (auto& flag : this->FlagTable) {
+ flag = nullptr;
}
}
-cmIDEOptions::~cmIDEOptions()
-{
-}
+cmIDEOptions::~cmIDEOptions() = default;
void cmIDEOptions::HandleFlag(std::string const& flag)
{
@@ -49,7 +47,7 @@ void cmIDEOptions::HandleFlag(std::string const& flag)
// If the last option expected a following value, this is it.
if (this->DoingFollowing) {
this->FlagMapUpdate(this->DoingFollowing, flag);
- this->DoingFollowing = 0;
+ this->DoingFollowing = nullptr;
return;
}
@@ -248,8 +246,7 @@ bool cmIDEOptions::HasFlag(std::string const& flag) const
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);
+ auto i = this->FlagMap.find(flag);
if (i != this->FlagMap.cend() && i->second.size() == 1) {
return i->second[0].c_str();
}
diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx
index 0974eea..5bf8320 100644
--- a/Source/cmInstalledFile.cxx
+++ b/Source/cmInstalledFile.cxx
@@ -21,7 +21,7 @@ cmInstalledFile::Property::~Property() = default;
void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name)
{
cmListFileBacktrace backtrace = mf->GetBacktrace();
- cmGeneratorExpression ge(backtrace);
+ cmGeneratorExpression ge(*mf->GetCMakeInstance(), backtrace);
this->Name = name;
this->NameExpression = ge.Parse(name);
@@ -56,7 +56,7 @@ void cmInstalledFile::AppendProperty(cmMakefile const* mf,
bool /*asString*/)
{
cmListFileBacktrace backtrace = mf->GetBacktrace();
- cmGeneratorExpression ge(backtrace);
+ cmGeneratorExpression ge(*mf->GetCMakeInstance(), backtrace);
Property& property = this->Properties[prop];
property.ValueExpressions.push_back(ge.Parse(value));
diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h
index 48decbc..f7151b5 100644
--- a/Source/cmJSONHelpers.h
+++ b/Source/cmJSONHelpers.h
@@ -36,26 +36,24 @@ struct cmJSONHelperBuilder
Object& Bind(const cm::string_view& name, M U::*member, F func,
bool required = true)
{
- return this->BindPrivate(name,
- [func, member](T& out, const Json::Value* value,
- CallState&&... state) -> E {
- return func(out.*member, value,
- std::forward(state)...);
- },
- required);
+ return this->BindPrivate(
+ name,
+ [func, member](T& out, const Json::Value* value, CallState&&... state)
+ -> E { return func(out.*member, value, std::forward(state)...); },
+ required);
}
template <typename M, typename F>
Object& Bind(const cm::string_view& name, std::nullptr_t, F func,
bool required = true)
{
- return this->BindPrivate(name,
- [func](T& /*out*/, const Json::Value* value,
- CallState&&... state) -> E {
- M dummy;
- return func(dummy, value,
- std::forward(state)...);
- },
- required);
+ return this->BindPrivate(
+ name,
+ [func](T& /*out*/, const Json::Value* value,
+ CallState&&... state) -> E {
+ M dummy;
+ return func(dummy, value, std::forward(state)...);
+ },
+ required);
}
template <typename F>
Object& Bind(const cm::string_view& name, F func, bool required = true)
diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx
index b1e9e56..ba0c138 100644
--- a/Source/cmLinkLineComputer.cxx
+++ b/Source/cmLinkLineComputer.cxx
@@ -87,13 +87,12 @@ 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);
+ return this->OutputConverter->ConvertToOutputFormat(input, shellFormat,
+ this->UseWatcomQuote);
}
std::string cmLinkLineComputer::ConvertToOutputForExisting(
@@ -102,13 +101,12 @@ std::string cmLinkLineComputer::ConvertToOutputForExisting(
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);
+ return this->OutputConverter->ConvertToOutputForExisting(
+ input, shellFormat, this->UseWatcomQuote);
}
std::string cmLinkLineComputer::ComputeLinkPath(
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index b2b724a..75ec694 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -430,7 +430,7 @@ void cmLocalGenerator::GenerateInstallRules()
// Compute the install prefix.
cmValue installPrefix =
this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
- std::string prefix = installPrefix;
+ std::string prefix = *installPrefix;
#if defined(_WIN32) && !defined(__CYGWIN__)
if (!installPrefix) {
@@ -869,7 +869,7 @@ std::string cmLocalGenerator::GetIncludeFlags(
cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang))) {
// if there is a separator then the flag is not repeated but is only
// given once i.e. -classpath a:b:c
- sep = incSep;
+ sep = *incSep;
repeatFlag = false;
}
@@ -1021,12 +1021,6 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
}
}
- std::string compReqFlag;
- this->AddCompilerRequirementFlag(compReqFlag, target, lang, config);
- if (!compReqFlag.empty()) {
- flags.emplace_back(std::move(compReqFlag));
- }
-
// Add Warning as errors flags
if (!this->GetCMakeInstance()->GetIgnoreWarningAsError()) {
const cmValue wError = target->GetProperty("COMPILE_WARNING_AS_ERROR");
@@ -1403,7 +1397,7 @@ void cmLocalGenerator::GetDeviceLinkFlags(
if (ipoEnabled) {
if (cmValue cudaIPOFlags = this->Makefile->GetDefinition(
"CMAKE_CUDA_DEVICE_LINK_OPTIONS_IPO")) {
- linkFlags += cudaIPOFlags;
+ linkFlags += *cudaIPOFlags;
}
}
@@ -1414,7 +1408,7 @@ void cmLocalGenerator::GetDeviceLinkFlags(
linkPath);
}
- // iterate link deps and see if any of them need IPO
+ this->AddVisibilityPresetFlags(linkFlags, target, "CUDA");
std::vector<std::string> linkOpts;
target->GetLinkOptions(linkOpts, config, "CUDA");
@@ -1854,7 +1848,7 @@ bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame(
[this, sysroot](std::string const& arch) -> bool {
std::string const& archSysroot =
this->AppleArchSysroots[arch];
- return cmIsOff(archSysroot) || sysroot == archSysroot;
+ return cmIsOff(archSysroot) || *sysroot == archSysroot;
});
}
@@ -1932,6 +1926,30 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"),
config);
+ // Add the language standard flag for compiling, and sometimes linking.
+ if (compileOrLink == cmBuildStep::Compile ||
+ (compileOrLink == cmBuildStep::Link &&
+ // Some toolchains require 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->Makefile->IsOn(
+ cmStrCat("CMAKE_", lang, "_LINK_WITH_STANDARD_COMPILE_OPTION")))) {
+ cmStandardLevelResolver standardResolver(this->Makefile);
+ std::string const& optionFlagDef =
+ standardResolver.GetCompileOptionDef(target, lang, config);
+ if (!optionFlagDef.empty()) {
+ cmValue 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);
+ }
+ }
+ }
+ }
+
std::string compiler = this->Makefile->GetSafeDefinition(
cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
@@ -2076,15 +2094,6 @@ 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, cmBuildStep::Link, lang, config);
if (target->IsIPOEnabled(lang, config)) {
@@ -2224,25 +2233,6 @@ void cmLocalGenerator::AddSharedFlags(std::string& 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()) {
- cmValue 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,
@@ -3387,7 +3377,12 @@ void cmLocalGenerator::AppendDefines(
if (!this->CheckDefinition(d.Value)) {
continue;
}
- defines.insert(d);
+ // remove any leading -D
+ if (cmHasLiteralPrefix(d.Value, "-D")) {
+ defines.emplace(d.Value.substr(2), d.Backtrace);
+ } else {
+ defines.insert(d);
+ }
}
}
@@ -3484,8 +3479,8 @@ 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();
+ if (cm::optional<std::string> comment = ccg.GetComment()) {
+ return *comment;
}
// Construct a reasonable default comment if possible.
@@ -4505,7 +4500,7 @@ std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex(
std::string const& o, cmListFileBacktrace const& bt)
{
std::vector<std::string> allConfigOutputs;
- cmGeneratorExpression ge(bt);
+ cmGeneratorExpression ge(*this->GetCMakeInstance(), bt);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o);
std::vector<std::string> configs =
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 765441c..20f23de 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -164,10 +164,6 @@ public:
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);
void AddColorDiagnosticsFlags(std::string& flags, const std::string& lang);
//! Append flags to a string.
virtual void AppendFlags(std::string& flags,
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index c11f5b4..1e2ea2a 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -701,7 +701,7 @@ bool cmLocalNinjaGenerator::HasUniqueByproducts(
{
std::vector<std::string> configs =
this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
- cmGeneratorExpression ge(bt);
+ cmGeneratorExpression ge(*this->GetCMakeInstance(), bt);
for (std::string const& p : byproducts) {
if (cmGeneratorExpression::Find(p) == std::string::npos) {
return false;
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index de1d3cd..7172d34 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -10,6 +10,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cm/vector>
#include <cmext/algorithm>
@@ -945,9 +946,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
// 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,
+ if (cm::optional<std::string> comment = ccg.GetComment()) {
+ this->AppendEcho(commands, *comment,
cmLocalUnixMakefileGenerator3::EchoGenerate);
}
}
diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx
index 4c0d2eea..8fe6677 100644
--- a/Source/cmLocalVisualStudio10Generator.cxx
+++ b/Source/cmLocalVisualStudio10Generator.cxx
@@ -18,8 +18,8 @@ class cmGeneratorTarget;
class cmVS10XMLParser : public cmXMLParser
{
public:
- virtual void EndElement(const std::string& /* name */) {}
- virtual void CharacterDataHandler(const char* data, int length)
+ void EndElement(const std::string& /* name */) override {}
+ void CharacterDataHandler(const char* data, int length) override
{
if (this->DoGUID) {
if (data[0] == '{') {
@@ -31,7 +31,7 @@ public:
this->DoGUID = false;
}
}
- virtual void StartElement(const std::string& name, const char**)
+ void StartElement(const std::string& name, const char**) override
{
// once the GUID is found do nothing
if (!this->GUID.empty()) {
@@ -41,7 +41,7 @@ public:
this->DoGUID = true;
}
}
- int InitializeParser()
+ int InitializeParser() override
{
this->DoGUID = false;
int ret = cmXMLParser::InitializeParser();
@@ -63,9 +63,7 @@ cmLocalVisualStudio10Generator::cmLocalVisualStudio10Generator(
{
}
-cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator()
-{
-}
+cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() = default;
void cmLocalVisualStudio10Generator::GenerateTarget(cmGeneratorTarget* target)
{
diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h
index 7bfe3b7..fe44bb5 100644
--- a/Source/cmLocalVisualStudio10Generator.h
+++ b/Source/cmLocalVisualStudio10Generator.h
@@ -24,7 +24,7 @@ public:
//! Set cache only and recurse to false by default.
cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf);
- virtual ~cmLocalVisualStudio10Generator();
+ ~cmLocalVisualStudio10Generator() override;
void ReadAndStoreExternalGUID(const std::string& name,
const char* path) override;
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index af2d31d..ded1647 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -10,6 +10,7 @@
#include <utility>
#include <cm/memory>
+#include <cm/optional>
#include <cmext/algorithm>
#include <windows.h>
@@ -56,7 +57,7 @@ public:
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);
+ std::string const& config, const char* isep = nullptr);
private:
cmLocalVisualStudio7Generator* LocalGenerator;
@@ -107,8 +108,8 @@ void cmLocalVisualStudio7Generator::Generate()
}
auto& gtVisited = this->GetSourcesVisited(gt);
- auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
- for (auto& d : deps) {
+ auto const& deps = this->GlobalGenerator->GetTargetDirectDepends(gt);
+ for (auto const& d : deps) {
// Take the union of visited source files of custom commands
auto depVisited = this->GetSourcesVisited(d);
gtVisited.insert(depVisited.begin(), depVisited.end());
@@ -126,7 +127,7 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets()
// 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) {
+ for (auto const& l : tgts) {
if (l->GetType() == cmStateEnums::GLOBAL_TARGET) {
cmCustomCommandLines force_commands =
cmMakeSingleCommandLine({ "cd", "." });
@@ -178,8 +179,7 @@ void cmLocalVisualStudio7Generator::WriteStampFiles()
// 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());
+ auto new_end = std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(new_end, listFiles.end());
for (const std::string& lf : listFiles) {
@@ -216,7 +216,7 @@ void cmLocalVisualStudio7Generator::GenerateTarget(cmGeneratorTarget* target)
// 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());
+ cmGeneratedFileStream fout(fname);
fout.SetCopyIfDifferent(true);
this->WriteVCProjFile(fout, lname, target);
if (fout.Close()) {
@@ -252,8 +252,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
// 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());
+ auto new_end = std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(new_end, listFiles.end());
std::string argS = cmStrCat("-S", this->GetSourceDirectory());
@@ -279,10 +278,9 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule()
// the generator validated all project-named sources.
file->ResolveFullPath();
return file;
- } else {
- cmSystemTools::Error("Error adding rule for " + makefileIn);
- return nullptr;
}
+ cmSystemTools::Error("Error adding rule for " + makefileIn);
+ return nullptr;
}
void cmLocalVisualStudio7Generator::WriteConfigurations(
@@ -558,12 +556,11 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranLinkFlagTable[] = {
class cmLocalVisualStudio7Generator::EventWriter
{
public:
- EventWriter(cmLocalVisualStudio7Generator* lg, const std::string& config,
+ EventWriter(cmLocalVisualStudio7Generator* lg, std::string config,
std::ostream& os)
: LG(lg)
- , Config(config)
+ , Config(std::move(config))
, Stream(os)
- , First(true)
{
}
void Start(const char* tool)
@@ -592,9 +589,8 @@ public:
{
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)
+ if (cm::optional<std::string> comment = ccg.GetComment()) {
+ this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(*comment)
<< "\"";
}
this->Stream << "\nCommandLine=\"";
@@ -610,7 +606,7 @@ private:
cmLocalVisualStudio7Generator* LG;
std::string Config;
std::ostream& Stream;
- bool First;
+ bool First = true;
};
void cmLocalVisualStudio7Generator::WriteConfiguration(
@@ -634,7 +630,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
// 1 == executable
// 10 == utility
const char* configType = "10";
- const char* projectType = 0;
+ const char* projectType = nullptr;
bool targetBuilds = true;
switch (target->GetType()) {
@@ -842,8 +838,26 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
}
fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
+ if (gg->IsMarmasmEnabled() && !this->FortranProject) {
+ Options marmasmOptions(this, Options::MarmasmCompiler, nullptr, nullptr);
+ /* clang-format off */
+ fout <<
+ "\t\t\t<Tool\n"
+ "\t\t\t\tName=\"MARMASM\"\n"
+ ;
+ /* clang-format on */
+ targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "ASM_MARMASM");
+ // Use same preprocessor definitions as VCCLCompilerTool.
+ targetOptions.OutputPreprocessorDefinitions(fout, 4, "ASM_MARMASM");
+ marmasmOptions.OutputFlagMap(fout, 4);
+ /* clang-format off */
+ fout <<
+ "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n"
+ "\t\t\t/>\n";
+ /* clang-format on */
+ }
if (gg->IsMasmEnabled() && !this->FortranProject) {
- Options masmOptions(this, Options::MasmCompiler, 0, 0);
+ Options masmOptions(this, Options::MasmCompiler, nullptr, nullptr);
/* clang-format off */
fout <<
"\t\t\t<Tool\n"
@@ -939,7 +953,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
}
std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
- std::string rootLinkerFlags, const std::string& configName)
+ std::string const& rootLinkerFlags, const std::string& configName)
{
std::string configTypeUpper = cmSystemTools::UpperCase(configName);
std::string extraLinkOptionsBuildTypeDef =
@@ -1421,8 +1435,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
fout << "\t<Files>\n";
// Loop through every source group.
- for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
- cmSourceGroup sg = sourceGroups[i];
+ for (auto const& sg : sourceGroups) {
this->WriteGroup(&sg, target, fout, libName, configs, sources);
}
@@ -1616,10 +1629,9 @@ std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
// 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;
+ for (auto& config : configs) {
+ if (config.size() > config_max.size()) {
+ config_max = config;
}
}
@@ -1645,9 +1657,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
// 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)) {
+ for (const auto& child : children) {
+ if (this->WriteGroup(&child, target, tmpOut, libName, configs, sources)) {
hasChildrenWithSources = true;
}
}
@@ -1673,8 +1684,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
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);
+ auto 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 =
@@ -1720,6 +1730,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
aCompilerTool = "VFCustomBuildTool";
}
}
+ if (gg->IsMarmasmEnabled() && !this->FortranProject &&
+ lang == "ASM_MARMASM") {
+ aCompilerTool = "MARMASM";
+ }
if (gg->IsMasmEnabled() && !this->FortranProject &&
lang == "ASM_MASM") {
aCompilerTool = "MASM";
@@ -1921,7 +1935,7 @@ void cmLocalVisualStudio7Generator::OutputTargetRules(
}
std::unique_ptr<cmCustomCommand> pcc(
this->MaybeCreateImplibDir(target, configName, this->FortranProject));
- if (pcc.get()) {
+ if (pcc) {
event.Write(*pcc);
}
event.Finish();
@@ -1964,7 +1978,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
/* clang-format off */
- fout << "<?xml version=\"1.0\" encoding = \""
+ fout << R"(<?xml version="1.0" encoding = ")"
<< gg->Encoding() << "\"?>\n"
<< "<VisualStudioProject\n"
<< "\tProjectCreator=\"Intel Fortran\"\n"
@@ -1972,7 +1986,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
/* clang-format on */
cmValue p = target->GetProperty("VS_KEYWORD");
const char* keyword = p ? p->c_str() : "Console Application";
- const char* projectType = 0;
+ const char* projectType = nullptr;
switch (target->GetType()) {
case cmStateEnums::OBJECT_LIBRARY:
case cmStateEnums::STATIC_LIBRARY:
@@ -1992,7 +2006,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran(
if (!keyword) {
keyword = "Console Application";
}
- projectType = 0;
+ projectType = nullptr;
break;
case cmStateEnums::UTILITY:
case cmStateEnums::GLOBAL_TARGET:
@@ -2026,7 +2040,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStart(
static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
/* clang-format off */
- fout << "<?xml version=\"1.0\" encoding = \""
+ fout << R"(<?xml version="1.0" encoding = ")"
<< gg->Encoding() << "\"?>\n"
<< "<VisualStudioProject\n"
<< "\tProjectType=\"Visual C++\"\n";
@@ -2050,6 +2064,17 @@ void cmLocalVisualStudio7Generator::WriteProjectStart(
<< "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
<< "\t</Platforms>\n";
/* clang-format on */
+ if (gg->IsMarmasmEnabled()) {
+ /* clang-format off */
+ fout <<
+ "\t<ToolFiles>\n"
+ "\t\t<DefaultToolFile\n"
+ "\t\t\tFileName=\"marmasm.rules\"\n"
+ "\t\t/>\n"
+ "\t</ToolFiles>\n"
+ ;
+ /* clang-format on */
+ }
if (gg->IsMasmEnabled()) {
/* clang-format off */
fout <<
@@ -2133,8 +2158,8 @@ void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent,
class cmVS7XMLParser : public cmXMLParser
{
public:
- virtual void EndElement(const std::string& /* name */) {}
- virtual void StartElement(const std::string& name, const char** atts)
+ void EndElement(const std::string& /* name */) override {}
+ void StartElement(const std::string& name, const char** atts) override
{
// once the GUID is found do nothing
if (!this->GUID.empty()) {
@@ -2159,7 +2184,7 @@ public:
}
}
}
- int InitializeParser()
+ int InitializeParser() override
{
int ret = cmXMLParser::InitializeParser();
if (ret == 0) {
@@ -2202,7 +2227,7 @@ static bool cmLVS7G_IsFAT(const char* dir)
volRoot[0] = dir[0];
char fsName[16];
if (GetVolumeInformationA(volRoot, 0, 0, 0, 0, 0, fsName, 16) &&
- strstr(fsName, "FAT") != 0) {
+ strstr(fsName, "FAT") != nullptr) {
return true;
}
}
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index d95ebc2..ce1156f 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -48,7 +48,7 @@ public:
//! Set cache only and recurse to false by default.
cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf);
- virtual ~cmLocalVisualStudio7Generator();
+ ~cmLocalVisualStudio7Generator() override;
cmLocalVisualStudio7Generator(const cmLocalVisualStudio7Generator&) = delete;
const cmLocalVisualStudio7Generator& operator=(
@@ -97,7 +97,7 @@ protected:
private:
using Options = cmVS7GeneratorOptions;
using FCInfo = cmLocalVisualStudio7GeneratorFCInfo;
- std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags,
+ std::string GetBuildTypeLinkerFlags(std::string const& rootLinkerFlags,
const std::string& configName);
void FixGlobalTargets();
void WriteVCProjHeader(std::ostream& fout, const std::string& libName,
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 2703c7b..58d46f1 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -4,6 +4,8 @@
#include <utility>
+#include <cm/memory>
+
#include "windows.h"
#include "cmCustomCommand.h"
@@ -24,9 +26,7 @@ cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator(
{
}
-cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
-{
-}
+cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator() = default;
cmGlobalVisualStudioGenerator::VSVersion
cmLocalVisualStudioGenerator::GetVersion() const
@@ -107,7 +107,7 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target,
// Add a pre-build event to create the directory.
cmCustomCommandLines commands = cmMakeSingleCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir });
- pcc.reset(new cmCustomCommand());
+ pcc = cm::make_unique<cmCustomCommand>();
pcc->SetCommandLines(commands);
pcc->SetStdPipesUTF8(true);
pcc->SetEscapeOldStyle(false);
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
index cf4f4d9..8fed1bd 100644
--- a/Source/cmLocalVisualStudioGenerator.h
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -29,7 +29,7 @@ class cmLocalVisualStudioGenerator : public cmLocalGenerator
{
public:
cmLocalVisualStudioGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
- virtual ~cmLocalVisualStudioGenerator();
+ ~cmLocalVisualStudioGenerator() override;
std::string ConstructScript(cmCustomCommandGenerator const& ccg,
const std::string& newline = "\n");
@@ -47,7 +47,7 @@ public:
void ComputeObjectFilenames(
std::map<cmSourceFile const*, std::string>& mapping,
- cmGeneratorTarget const* = 0) override;
+ cmGeneratorTarget const* = nullptr) override;
protected:
virtual const char* ReportErrorLabel() const;
diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx
index e7a1f93..759ee7b 100644
--- a/Source/cmLocalXCodeGenerator.cxx
+++ b/Source/cmLocalXCodeGenerator.cxx
@@ -147,7 +147,7 @@ void cmLocalXCodeGenerator::AddXCConfigSources(cmGeneratorTarget* target)
for (auto& config : configs) {
auto file = cmGeneratorExpression::Evaluate(
- xcconfig,
+ *xcconfig,
this, config);
if (!file.empty()) {
target->AddSource(file);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 6e0d704..d26f383 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -375,19 +375,28 @@ public:
++this->Makefile->RecursionDepth;
this->Makefile->ExecutionStatusStack.push_back(&status);
#if !defined(CMAKE_BOOTSTRAP)
- if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
- this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff,
- lfc);
- }
+ this->ProfilingDataRAII =
+ this->Makefile->GetCMakeInstance()->CreateProfilingEntry(
+ "script", lff.LowerCaseName(), [&lff, &lfc]() -> Json::Value {
+ Json::Value argsValue = Json::objectValue;
+ if (!lff.Arguments().empty()) {
+ std::string args;
+ for (auto const& a : lff.Arguments()) {
+ args = cmStrCat(args, args.empty() ? "" : " ", a.Value);
+ }
+ argsValue["functionArgs"] = args;
+ }
+ argsValue["location"] =
+ cmStrCat(lfc.FilePath, ':', std::to_string(lfc.Line));
+ return argsValue;
+ });
#endif
}
~cmMakefileCall()
{
#if !defined(CMAKE_BOOTSTRAP)
- if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
- this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry();
- }
+ this->ProfilingDataRAII.reset();
#endif
this->Makefile->ExecutionStatusStack.pop_back();
--this->Makefile->RecursionDepth;
@@ -399,6 +408,9 @@ public:
private:
cmMakefile* Makefile;
+#if !defined(CMAKE_BOOTSTRAP)
+ cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII;
+#endif
};
void cmMakefile::OnExecuteCommand(std::function<void()> callback)
@@ -971,7 +983,8 @@ void cmMakefile::Generate(cmLocalGenerator& lg)
this->DoGenerate(lg);
cmValue oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
if (oldValue &&
- cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
+ cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, *oldValue,
+ "2.4")) {
this->GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
"You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
@@ -3584,6 +3597,9 @@ int cmMakefile::TryCompile(const std::string& srcdir,
gg->RecursionDepth = this->RecursionDepth;
cm.SetGlobalGenerator(std::move(gg));
+ // copy trace state
+ cm.SetTraceRedirect(this->GetCMakeInstance());
+
// do a configure
cm.SetHomeDirectory(srcdir);
cm.SetHomeOutputDirectory(bindir);
@@ -4470,12 +4486,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
}
// Deprecate old policies.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0108 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 ||
- id == cmPolicies::CMP0091)) &&
+ id == cmPolicies::CMP0091 || id == cmPolicies::CMP0104)) &&
(!this->IsSet("CMAKE_WARN_DEPRECATED") ||
this->IsOn("CMAKE_WARN_DEPRECATED"))) {
this->IssueMessage(MessageType::DEPRECATION_WARNING,
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 54f03b9..e53d28c 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -537,12 +537,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
cmOutputConverter::SHELL);
vars.ObjectDir = objectDir.c_str();
- cmOutputConverter::OutputFormat output = (useWatcomQuote)
- ? cmOutputConverter::WATCOMQUOTE
- : cmOutputConverter::SHELL;
std::string target = this->LocalGenerator->ConvertToOutputFormat(
this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
- output);
+ cmOutputConverter::SHELL, useWatcomQuote);
vars.Target = target.c_str();
vars.TargetPDB = targetOutPathPDB.c_str();
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 45ef8c8..9669293 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -756,12 +756,9 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
cmOutputConverter::SHELL);
vars.ObjectDir = objectDir.c_str();
- cmOutputConverter::OutputFormat output = (useWatcomQuote)
- ? cmOutputConverter::WATCOMQUOTE
- : cmOutputConverter::SHELL;
std::string target = this->LocalGenerator->ConvertToOutputFormat(
this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
- output);
+ cmOutputConverter::SHELL, useWatcomQuote);
vars.Target = target.c_str();
vars.LinkLibraries = linkLibs.c_str();
vars.ObjectsQuoted = buildObjs.c_str();
@@ -824,7 +821,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
if (useArchiveRules) {
// Construct the individual object list strings.
std::vector<std::string> object_strings;
- this->WriteObjectsStrings(object_strings, archiveCommandLimit);
+ this->WriteObjectsStrings(object_strings, false, 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
diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx
index 1cd97c9..e903ae1 100644
--- a/Source/cmMakefileProfilingData.cxx
+++ b/Source/cmMakefileProfilingData.cxx
@@ -4,7 +4,8 @@
#include <chrono>
#include <stdexcept>
-#include <vector>
+#include <type_traits>
+#include <utility>
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
@@ -12,7 +13,6 @@
#include "cmsys/FStream.hxx"
#include "cmsys/SystemInformation.hxx"
-#include "cmListFileCache.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -43,8 +43,9 @@ cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
}
}
-void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
- cmListFileContext const& lfc)
+void cmMakefileProfilingData::StartEntry(const std::string& category,
+ const std::string& name,
+ cm::optional<Json::Value> args)
{
/* Do not try again if we previously failed to write to output. */
if (!this->ProfileStream.good()) {
@@ -58,24 +59,17 @@ void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
cmsys::SystemInformation info;
Json::Value v;
v["ph"] = "B";
- v["name"] = lff.LowerCaseName();
- v["cat"] = "cmake";
+ v["name"] = name;
+ v["cat"] = category;
v["ts"] = static_cast<Json::Value::UInt64>(
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
v["pid"] = static_cast<int>(info.GetProcessId());
v["tid"] = 0;
- Json::Value argsValue;
- if (!lff.Arguments().empty()) {
- std::string args;
- for (auto const& a : lff.Arguments()) {
- args += (args.empty() ? "" : " ") + a.Value;
- }
- argsValue["functionArgs"] = args;
+ if (args) {
+ v["args"] = *std::move(args);
}
- argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line);
- v["args"] = argsValue;
this->JsonWriter->write(v, &this->ProfileStream);
} catch (std::ios_base::failure& fail) {
@@ -112,3 +106,36 @@ void cmMakefileProfilingData::StopEntry()
cmSystemTools::Error("Error writing profiling output!");
}
}
+
+cmMakefileProfilingData::RAII::RAII(cmMakefileProfilingData& data,
+ const std::string& category,
+ const std::string& name,
+ cm::optional<Json::Value> args)
+ : Data(&data)
+{
+ this->Data->StartEntry(category, name, std::move(args));
+}
+
+cmMakefileProfilingData::RAII::RAII(RAII&& other) noexcept
+ : Data(other.Data)
+{
+ other.Data = nullptr;
+}
+
+cmMakefileProfilingData::RAII::~RAII()
+{
+ if (this->Data) {
+ this->Data->StopEntry();
+ }
+}
+
+cmMakefileProfilingData::RAII& cmMakefileProfilingData::RAII::operator=(
+ RAII&& other) noexcept
+{
+ if (this->Data) {
+ this->Data->StopEntry();
+ }
+ this->Data = other.Data;
+ other.Data = nullptr;
+ return *this;
+}
diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h
index a86764a..4cf0bfa 100644
--- a/Source/cmMakefileProfilingData.h
+++ b/Source/cmMakefileProfilingData.h
@@ -4,23 +4,45 @@
#include <memory>
#include <string>
+#include <cm/optional>
+
+#include <cm3p/json/value.h> // IWYU pragma: keep
+
#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 StartEntry(const std::string& category, const std::string& name,
+ cm::optional<Json::Value> args = cm::nullopt);
void StopEntry();
+ class RAII
+ {
+ public:
+ RAII() = delete;
+ RAII(const RAII&) = delete;
+ RAII(RAII&&) noexcept;
+
+ RAII(cmMakefileProfilingData& data, const std::string& category,
+ const std::string& name,
+ cm::optional<Json::Value> args = cm::nullopt);
+
+ ~RAII();
+
+ RAII& operator=(const RAII&) = delete;
+ RAII& operator=(RAII&&) noexcept;
+
+ private:
+ cmMakefileProfilingData* Data = nullptr;
+ };
+
private:
cmsys::ofstream ProfileStream;
std::unique_ptr<Json::StreamWriter> JsonWriter;
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index d19bbb9..c40d685 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -25,6 +25,7 @@
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
+#include "cmGlobalCommonGenerator.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLinkLineComputer.h" // IWYU pragma: keep
#include "cmLocalCommonGenerator.h"
@@ -1031,7 +1032,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
}
this->GlobalGenerator->AddCXXCompileCommand(
- source.GetFullPath(), workingDirectory, compileCommand);
+ source.GetFullPath(), workingDirectory, compileCommand, relativeObj);
}
// See if we need to use a compiler launcher like ccache or distcc
@@ -1107,8 +1108,29 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
} else {
driverMode = lang == "C" ? "gcc" : "g++";
}
+ std::string d =
+ this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang);
+ std::string exportFixes;
+ if (!d.empty()) {
+ this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d);
+ std::string fixesFile = cmSystemTools::CollapseFullPath(cmStrCat(
+ d, '/',
+ this->LocalGenerator->MaybeRelativeToTopBinDir(cmStrCat(
+ this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+ this->LocalGenerator->GetTargetDirectory(
+ this->GeneratorTarget),
+ '/', objectName, ".yaml"))));
+ this->GlobalCommonGenerator->AddClangTidyExportFixesFile(
+ fixesFile);
+ cmSystemTools::MakeDirectory(
+ cmSystemTools::GetFilenamePath(fixesFile));
+ fixesFile =
+ this->LocalGenerator->MaybeRelativeToCurBinDir(fixesFile);
+ exportFixes = cmStrCat(";--export-fixes=", fixesFile);
+ }
run_iwyu += this->LocalGenerator->EscapeForShell(
- cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
+ cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode,
+ exportFixes));
}
if (cmNonempty(cpplint)) {
run_iwyu += " --cpplint=";
@@ -1472,11 +1494,11 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
/* clang-format off */
*this->InfoFileStream
<< "\n"
- << "# Targets to which this target links.\n"
- << "set(CMAKE_TARGET_LINKED_INFO_FILES\n";
+ "# Targets to which this target links which contain Fortran sources.\n"
+ "set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES\n";
/* clang-format on */
std::vector<std::string> dirs =
- this->GetLinkedTargetDirectories(this->GetConfigName());
+ this->GetLinkedTargetDirectories("Fortran", this->GetConfigName());
for (std::string const& d : dirs) {
*this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n";
}
@@ -1866,10 +1888,12 @@ class cmMakefileTargetGeneratorObjectStrings
public:
cmMakefileTargetGeneratorObjectStrings(std::vector<std::string>& strings,
cmOutputConverter* outputConverter,
+ bool useWatcomQuote,
cmStateDirectory const& stateDir,
std::string::size_type limit)
: Strings(strings)
, OutputConverter(outputConverter)
+ , UseWatcomQuote(useWatcomQuote)
, StateDir(stateDir)
, LengthLimit(limit)
{
@@ -1880,7 +1904,7 @@ public:
// Construct the name of the next object.
this->NextObject = this->OutputConverter->ConvertToOutputFormat(
this->OutputConverter->MaybeRelativeToCurBinDir(obj),
- cmOutputConverter::RESPONSE);
+ cmOutputConverter::RESPONSE, this->UseWatcomQuote);
// Roll over to next string if the limit will be exceeded.
if (this->LengthLimit != std::string::npos &&
@@ -1903,6 +1927,7 @@ public:
private:
std::vector<std::string>& Strings;
cmOutputConverter* OutputConverter;
+ bool UseWatcomQuote;
cmStateDirectory StateDir;
std::string::size_type LengthLimit;
std::string CurrentString;
@@ -1911,12 +1936,13 @@ private:
};
void cmMakefileTargetGenerator::WriteObjectsStrings(
- std::vector<std::string>& objStrings, std::string::size_type limit)
+ std::vector<std::string>& objStrings, bool useWatcomQuote,
+ std::string::size_type limit)
{
cmValue pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
cmMakefileTargetGeneratorObjectStrings helper(
- objStrings, this->LocalGenerator,
+ objStrings, this->LocalGenerator, useWatcomQuote,
this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit);
for (std::string const& obj : this->Objects) {
if (cmHasSuffix(obj, pchExtension)) {
@@ -2237,7 +2263,8 @@ void cmMakefileTargetGenerator::CreateObjectLists(
// Construct the individual object list strings.
std::vector<std::string> object_strings;
- this->WriteObjectsStrings(object_strings, responseFileLimit);
+ this->WriteObjectsStrings(object_strings, useWatcomQuote,
+ responseFileLimit);
// Lookup the response file reference flag.
std::string responseFlag = this->GetResponseFlag(responseMode);
@@ -2249,6 +2276,7 @@ void cmMakefileTargetGenerator::CreateObjectLists(
std::string responseFileName =
(responseMode == Link) ? "objects" : "deviceObjects";
responseFileName += std::to_string(i + 1);
+ responseFileName += ".rsp";
// Create this response file.
std::string objects_rsp = this->CreateResponseFile(
@@ -2266,7 +2294,7 @@ void cmMakefileTargetGenerator::CreateObjectLists(
} else if (useLinkScript) {
if (!useArchiveRules) {
std::vector<std::string> objStrings;
- this->WriteObjectsStrings(objStrings);
+ this->WriteObjectsStrings(objStrings, useWatcomQuote);
buildObjs = objStrings[0];
}
} else {
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index dafa650..5d614fe 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -123,6 +123,7 @@ protected:
std::string& variableNameExternal,
bool useWatcomQuote);
void WriteObjectsStrings(std::vector<std::string>& objStrings,
+ bool useWatcomQuote,
std::string::size_type limit = std::string::npos);
// write the driver rule to build target outputs
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index fa29ec9..52373f3 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -8,6 +8,7 @@
#include <cm/string_view>
#include <cmext/string_view>
+#include "cmConfigureLog.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -64,6 +65,23 @@ void ReportCheckResult(cm::string_view what, std::string result,
}
}
+namespace {
+#ifndef CMAKE_BOOTSTRAP
+void WriteMessageEvent(cmConfigureLog& log, cmMakefile const& mf,
+ std::string const& message)
+{
+ // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
+ static const std::vector<unsigned long> LogVersionsWithMessageV1{ 1 };
+
+ if (log.IsAnyLogVersionEnabled(LogVersionsWithMessageV1)) {
+ log.BeginEvent("message-v1", mf);
+ log.WriteLiteralTextBlock("message"_s, message);
+ log.EndEvent();
+ }
+}
+#endif
+}
+
} // anonymous namespace
// cmLibraryCommand
@@ -121,6 +139,14 @@ bool cmMessageCommand(std::vector<std::string> const& args,
level = Message::LogLevel::LOG_STATUS;
checkingType = CheckingType::CHECK_FAIL;
++i;
+ } else if (*i == "CONFIGURE_LOG") {
+#ifndef CMAKE_BOOTSTRAP
+ if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
+ ++i;
+ WriteMessageEvent(*log, mf, cmJoin(cmMakeRange(i, args.cend()), ""_s));
+ }
+#endif
+ return true;
} else if (*i == "STATUS") {
level = Message::LogLevel::LOG_STATUS;
++i;
diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx
index 333003b..ff513be 100644
--- a/Source/cmMessenger.cxx
+++ b/Source/cmMessenger.cxx
@@ -107,8 +107,8 @@ static void printMessageText(std::ostream& msg, std::string const& text)
{
msg << ":\n";
cmDocumentationFormatter formatter;
- formatter.SetIndent(" ");
- formatter.PrintFormatted(msg, text.c_str());
+ formatter.SetIndent(2u);
+ formatter.PrintFormatted(msg, text);
}
static void displayMessage(MessageType t, std::ostringstream& msg)
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index bda8a5f..a1633ca 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -64,9 +64,9 @@ 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());
+ cmSystemTools::Error(
+ cmStrCat("CMake can not determine linker language for target: ",
+ this->GetGeneratorTarget()->GetName()));
return;
}
@@ -117,7 +117,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
#ifdef NINJA_GEN_VERBOSE_FILES
cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
this->GetRulesFileStream()
- << "# Rules for each languages for "
+ << "# Rules for each language for "
<< cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
<< " target " << this->GetTargetName() << "\n\n";
#endif
@@ -372,7 +372,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
vars.SwiftModule = "$SWIFT_MODULE";
vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
- vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP";
vars.SwiftSources = "$SWIFT_SOURCES";
vars.Defines = "$DEFINES";
@@ -645,14 +644,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd(
} 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");
@@ -948,6 +940,37 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
this->WriteNvidiaDeviceLinkRule(usedResponseFile, config);
}
+/// Get the target property if it exists, or return a default
+static std::string GetTargetPropertyOrDefault(cmGeneratorTarget const* target,
+ std::string const& property,
+ std::string defaultValue)
+{
+ if (cmValue name = target->GetProperty(property)) {
+ return *name;
+ }
+ return defaultValue;
+}
+
+/// Compute the swift module name for target
+static std::string GetSwiftModuleName(cmGeneratorTarget const* target)
+{
+ return GetTargetPropertyOrDefault(target, "Swift_MODULE_NAME",
+ target->GetName());
+}
+
+/// Compute the swift module path for the target
+/// The returned path will need to be converted to the generator path
+static std::string GetSwiftModulePath(cmGeneratorTarget const* target)
+{
+ std::string moduleName = GetSwiftModuleName(target);
+ std::string moduleDirectory = GetTargetPropertyOrDefault(
+ target, "Swift_MODULE_DIRECTORY",
+ target->LocalGenerator->GetCurrentBinaryDirectory());
+ std::string moduleFileName = GetTargetPropertyOrDefault(
+ target, "Swift_MODULE", moduleName + ".swiftmodule");
+ return moduleDirectory + "/" + moduleFileName;
+}
+
void cmNinjaNormalTargetGenerator::WriteLinkStatement(
const std::string& config, const std::string& fileConfig,
bool firstForConfig)
@@ -1046,37 +1069,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
return targetNames.Base;
}();
- vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string {
- if (cmValue 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 (cmValue prop = this->GetGeneratorTarget()->GetProperty(
- "Swift_MODULE_DIRECTORY")) {
- directory = *prop;
- }
-
- std::string name = module + ".swiftmodule";
- if (cmValue 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_MODULE_NAME"] = GetSwiftModuleName(gt);
+ vars["SWIFT_MODULE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
+ this->ConvertToNinjaPath(GetSwiftModulePath(gt)),
+ cmOutputConverter::SHELL);
vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
std::vector<cmSourceFile const*> sources;
@@ -1101,6 +1097,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
vars["DEFINES"] = this->GetDefines("Swift", config);
vars["FLAGS"] = this->GetFlags("Swift", config);
vars["INCLUDES"] = this->GetIncludes("Swift", config);
+ this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]);
}
// Compute specific libraries to link with.
@@ -1118,7 +1115,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
this->GetObjectFilePath(source, config));
}
}
- linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
+ if (targetType != cmStateEnums::EXECUTABLE ||
+ gt->IsExecutableWithExports()) {
+ linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
+ }
} else {
linkBuild.ExplicitDeps = this->GetObjects(config);
}
@@ -1232,16 +1232,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
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);
+ cmGeneratorTarget::NameComponents const& components =
+ gt->GetFullNameComponents(config);
std::string dbg_suffix = ".dbg";
// TODO: Where to document?
if (cmValue d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
dbg_suffix = *d;
}
- vars["TARGET_PDB"] = base + suffix + dbg_suffix;
+ vars["TARGET_PDB"] = components.base + components.suffix + dbg_suffix;
}
const std::string objPath =
@@ -1398,6 +1396,23 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
}
}
+ // Add dependencies on swiftmodule files when using the swift linker
+ if (this->TargetLinkLanguage(config) == "Swift") {
+ if (cmComputeLinkInformation* cli =
+ this->GeneratorTarget->GetLinkInformation(config)) {
+ for (auto const& dependency : cli->GetItems()) {
+ // Both the current target and the linked target must be swift targets
+ // in order for there to be a swiftmodule to depend on
+ if (dependency.Target &&
+ dependency.Target->GetLinkerLanguage(config) == "Swift") {
+ std::string swiftmodule =
+ this->ConvertToNinjaPath(GetSwiftModulePath(dependency.Target));
+ linkBuild.ImplicitDeps.emplace_back(swiftmodule);
+ }
+ }
+ }
+ }
+
// Ninja should restat after linking if and only if there are byproducts.
vars["RESTAT"] = byproducts.ExplicitOuts.empty() ? "" : "1";
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index e4427f5..13782b0 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -4,6 +4,7 @@
#include <algorithm>
#include <cassert>
+#include <functional>
#include <iterator>
#include <map>
#include <ostream>
@@ -21,17 +22,13 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
-#include "cmExportBuildFileGenerator.h"
-#include "cmExportSet.h"
+#include "cmDyndepCollation.h"
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
+#include "cmGlobalCommonGenerator.h"
#include "cmGlobalNinjaGenerator.h"
-#include "cmInstallCxxModuleBmiGenerator.h"
-#include "cmInstallExportGenerator.h"
-#include "cmInstallFileSetGenerator.h"
-#include "cmInstallGenerator.h"
#include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h"
@@ -47,7 +44,6 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
-#include "cmTargetExport.h"
#include "cmValue.h"
#include "cmake.h"
@@ -109,12 +105,13 @@ cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
}
std::string cmNinjaTargetGenerator::LanguageCompilerRule(
- const std::string& lang, const std::string& config) const
+ const std::string& lang, const std::string& config,
+ WithScanning withScanning) const
{
return cmStrCat(
lang, "_COMPILER__",
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
- '_', config);
+ withScanning == WithScanning::Yes ? "_scanned_" : "_unscanned_", config);
}
std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule(
@@ -156,23 +153,6 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule(
'_', config);
}
-bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
- std::string const& lang, std::string const& config) const
-{
- if (lang != "CXX"_s) {
- return false;
- }
- return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) ==
- cmGeneratorTarget::Cxx20SupportLevel::Supported &&
- 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)
{
@@ -256,54 +236,17 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
}
- auto const& path = source->GetFullPath();
- auto const* tgt = this->GeneratorTarget->Target;
-
- std::string file_set_type;
-
- for (auto const& name : tgt->GetAllFileSetNames()) {
- auto const* file_set = tgt->GetFileSet(name);
- if (!file_set) {
+ auto const* fs = this->GeneratorTarget->GetFileSetForSource(config, source);
+ if (fs &&
+ (fs->GetType() == "CXX_MODULES"_s ||
+ fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) {
+ if (source->GetLanguage() != "CXX"_s) {
this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(),
- "\" is tracked to have file set \"", name,
- "\", but it was not found."));
- continue;
- }
-
- auto fileEntries = file_set->CompileFileEntries();
- auto directoryEntries = file_set->CompileDirectoryEntries();
- auto directories = file_set->EvaluateDirectoryEntries(
- directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
-
- std::map<std::string, std::vector<std::string>> files;
- for (auto const& entry : fileEntries) {
- file_set->EvaluateFileEntry(directories, files, entry,
- this->LocalGenerator, config,
- this->GeneratorTarget);
- }
-
- for (auto const& it : files) {
- for (auto const& filename : it.second) {
- if (filename == path) {
- file_set_type = file_set->GetType();
- break;
- }
- }
- }
-
- if (file_set_type == "CXX_MODULES"_s ||
- file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
- if (source->GetLanguage() != "CXX"_s) {
- this->GetMakefile()->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(
- "Target \"", tgt->GetName(), "\" contains the source\n ", path,
- "\nin a file set of type \"", file_set_type,
- R"(" but the source is not classified as a "CXX" source.)"));
- continue;
- }
+ MessageType::FATAL_ERROR,
+ cmStrCat("Target \"", this->GeneratorTarget->Target->GetName(),
+ "\" contains the source\n ", source->GetFullPath(),
+ "\nin a file set of type \"", fs->GetType(),
+ R"(" but the source is not classified as a "CXX" source.)"));
}
}
@@ -452,6 +395,24 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath(
return path;
}
+std::string cmNinjaTargetGenerator::GetClangTidyReplacementsFilePath(
+ const std::string& directory, cmSourceFile const* source,
+ const std::string& config) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty()) {
+ path += '/';
+ }
+ path = cmStrCat(directory, '/', path);
+ std::string const& objectName = this->GeneratorTarget->GetObjectName(source);
+ path =
+ cmStrCat(std::move(path),
+ this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+ this->GetGlobalGenerator()->ConfigDirectory(config), '/',
+ objectName, ".yaml");
+ return path;
+}
+
std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
cmSourceFile const* source, const std::string& config) const
{
@@ -600,9 +561,9 @@ cmNinjaRule GetScanRule(
// Scanning always uses a depfile for preprocessor dependencies.
if (deptype == "msvc"_s) {
rule.DepType = deptype;
- rule.DepFile = "";
+ rule.DepFile.clear();
} else {
- rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepType.clear(); // no deps= for multiple outputs
rule.DepFile = "$DEP_FILE";
}
@@ -650,6 +611,19 @@ cmNinjaRule GetScanRule(
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
const std::string& config)
{
+ // For some cases we scan to dynamically discover dependencies.
+ bool const needDyndep = this->GetGeneratorTarget()->NeedDyndep(lang, config);
+
+ if (needDyndep) {
+ this->WriteCompileRule(lang, config, WithScanning::Yes);
+ }
+ this->WriteCompileRule(lang, config, WithScanning::No);
+}
+
+void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
+ const std::string& config,
+ WithScanning withScanning)
+{
cmRulePlaceholderExpander::RuleVariables vars;
vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
vars.CMTargetType =
@@ -669,7 +643,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
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";
@@ -707,7 +680,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
this->GetLocalGenerator()->ConvertToOutputFormat(
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- if (needDyndep) {
+ if (withScanning == WithScanning::Yes) {
const auto& scanDepType = this->GetMakefile()->GetSafeDefinition(
cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_DEPFILE_FORMAT"));
@@ -813,7 +786,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
this->GetGlobalGenerator()->AddRule(rule);
}
- cmNinjaRule rule(this->LanguageCompilerRule(lang, config));
+ cmNinjaRule rule(this->LanguageCompilerRule(lang, config, withScanning));
// If using a response file, move defines, includes, and flags into it.
if (!responseFlag.empty()) {
rule.RspFile = "$RSP_FILE";
@@ -867,7 +840,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
}
}
- if (needDyndep && !modmapFormat.empty()) {
+ if (withScanning == WithScanning::Yes && !modmapFormat.empty()) {
std::string modmapFlags = mf->GetRequiredDefinition(
cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG"));
cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>",
@@ -978,8 +951,24 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
} else {
driverMode = lang == "C" ? "gcc" : "g++";
}
+ const bool haveClangTidyExportFixesDir =
+ !this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang)
+ .empty();
+ std::string exportFixes;
+ if (haveClangTidyExportFixesDir) {
+ exportFixes = ";--export-fixes=$CLANG_TIDY_EXPORT_FIXES";
+ }
run_iwyu += this->GetLocalGenerator()->EscapeForShell(
- cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
+ cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode,
+ exportFixes));
+ if (haveClangTidyExportFixesDir) {
+ std::string search = cmStrCat(
+ this->GetLocalGenerator()->GetState()->UseWindowsShell() ? ""
+ : "\\",
+ "$$CLANG_TIDY_EXPORT_FIXES");
+ auto loc = run_iwyu.rfind(search);
+ run_iwyu.replace(loc, search.length(), "$CLANG_TIDY_EXPORT_FIXES");
+ }
}
if (cmNonempty(cpplint)) {
run_iwyu += cmStrCat(
@@ -1177,30 +1166,42 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
}
this->GetImplFileStream(fileConfig) << "\n";
+}
- if (!this->Configs[config].SwiftOutputMap.empty()) {
- std::string const mapFilePath =
- cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
- "output-file-map.json");
- std::string const targetSwiftDepsPath = [this, config]() -> std::string {
- cmGeneratorTarget const* target = this->GeneratorTarget;
- if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
- return *name;
- }
- return this->ConvertToNinjaPath(
- cmStrCat(target->GetSupportDirectory(), '/', config, '/',
- target->GetName(), ".swiftdeps"));
- }();
+void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap(
+ const std::string& config, std::string& flags)
+{
+ if (this->Configs[config].SwiftOutputMap.empty()) {
+ return;
+ }
+
+ std::string const targetSwiftDepsPath = [this, config]() -> std::string {
+ cmGeneratorTarget const* target = this->GeneratorTarget;
+ if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
+ return *name;
+ }
+ return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(),
+ '/', config, '/',
+ target->GetName(), ".swiftdeps"));
+ }();
- // build the global target dependencies
- // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
- Json::Value deps(Json::objectValue);
- deps["swift-dependencies"] = targetSwiftDepsPath;
- this->Configs[config].SwiftOutputMap[""] = deps;
+ std::string mapFilePath =
+ cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
+ "output-file-map.json");
- cmGeneratedFileStream output(mapFilePath);
- output << this->Configs[config].SwiftOutputMap;
- }
+ // build the global target dependencies
+ // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps
+ Json::Value deps(Json::objectValue);
+ deps["swift-dependencies"] = targetSwiftDepsPath;
+ this->Configs[config].SwiftOutputMap[""] = deps;
+
+ cmGeneratedFileStream output(mapFilePath);
+ output << this->Configs[config].SwiftOutputMap;
+
+ // Add flag
+ this->LocalGenerator->AppendFlags(flags, "-output-file-map");
+ this->LocalGenerator->AppendFlagEscape(flags,
+ ConvertToNinjaPath(mapFilePath));
}
namespace {
@@ -1315,8 +1316,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
!(language == "RC" || (language == "CUDA" && !flag));
int const commandLineLengthLimit =
((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;
+ bool const needDyndep =
+ this->GeneratorTarget->NeedDyndepForSource(language, config, source);
- cmNinjaBuild objBuild(this->LanguageCompilerRule(language, config));
+ cmNinjaBuild objBuild(this->LanguageCompilerRule(
+ language, config, needDyndep ? WithScanning::Yes : WithScanning::No));
cmNinjaVars& vars = objBuild.Variables;
vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config);
vars["DEFINES"] = this->ComputeDefines(source, language, config);
@@ -1345,6 +1349,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
}
+ std::string d =
+ this->GeneratorTarget->GetClangTidyExportFixesDirectory(language);
+ if (!d.empty()) {
+ this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d);
+ std::string fixesFile =
+ this->GetClangTidyReplacementsFilePath(d, source, config);
+ this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile);
+ cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(fixesFile));
+ fixesFile = this->ConvertToNinjaPath(fixesFile);
+ vars["CLANG_TIDY_EXPORT_FIXES"] = fixesFile;
+ }
+
if (firstForConfig) {
this->ExportObjectCompileCommand(
language, sourceFilePath, objectDir, objectFileName, objectFileDir,
@@ -1425,7 +1441,6 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
// For some cases we scan to dynamically discover dependencies.
- bool const needDyndep = this->NeedDyndep(language, config);
bool const compilationPreprocesses =
!this->NeedExplicitPreprocessing(language);
@@ -1660,218 +1675,19 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang,
Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
Json::arrayValue;
- for (std::string const& l : this->GetLinkedTargetDirectories(config)) {
+ for (std::string const& l : this->GetLinkedTargetDirectories(lang, config)) {
tdi_linked_target_dirs.append(l);
}
- cmTarget* tgt = this->GeneratorTarget->Target;
- auto all_file_sets = tgt->GetAllFileSetNames();
- Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue;
- for (auto const& file_set_name : all_file_sets) {
- auto* file_set = tgt->GetFileSet(file_set_name);
- if (!file_set) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(),
- "\" is tracked to have file set \"", file_set_name,
- "\", but it was not found."));
- continue;
- }
- auto fs_type = file_set->GetType();
- // We only care about C++ module sources here.
- if (fs_type != "CXX_MODULES"_s) {
- continue;
- }
-
- auto fileEntries = file_set->CompileFileEntries();
- auto directoryEntries = file_set->CompileDirectoryEntries();
-
- auto directories = file_set->EvaluateDirectoryEntries(
- directoryEntries, this->GeneratorTarget->LocalGenerator, config,
- this->GeneratorTarget);
- std::map<std::string, std::vector<std::string>> files_per_dirs;
- for (auto const& entry : fileEntries) {
- file_set->EvaluateFileEntry(directories, files_per_dirs, entry,
- this->GeneratorTarget->LocalGenerator,
- config, this->GeneratorTarget);
- }
-
- std::map<std::string, cmSourceFile const*> sf_map;
- {
- std::vector<cmSourceFile const*> objectSources;
- this->GeneratorTarget->GetObjectSources(objectSources, config);
- for (auto const* sf : objectSources) {
- auto full_path = sf->GetFullPath();
- if (full_path.empty()) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(),
- "\" has a full path-less source file."));
- continue;
- }
- sf_map[full_path] = sf;
- }
- }
-
- Json::Value fs_dest = Json::nullValue;
- for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
- if (auto const* fsg =
- dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) {
- if (fsg->GetTarget() == this->GeneratorTarget &&
- fsg->GetFileSet() == file_set) {
- fs_dest = fsg->GetDestination(config);
- continue;
- }
- }
- }
-
- for (auto const& files_per_dir : files_per_dirs) {
- for (auto const& file : files_per_dir.second) {
- auto lookup = sf_map.find(file);
- if (lookup == sf_map.end()) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
- file,
- R"(" which is not in any of its "FILE_SET BASE_DIRS".)"));
- continue;
- }
-
- auto const* sf = lookup->second;
-
- if (!sf) {
- this->GetMakefile()->IssueMessage(
- MessageType::INTERNAL_ERROR,
- cmStrCat("Target \"", tgt->GetName(), "\" has source file \"",
- file, "\" which has not been tracked properly."));
- continue;
- }
-
- auto obj_path = this->GetObjectFilePath(sf, config);
- Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
- Json::objectValue;
-
- tdi_module_info["source"] = file;
- tdi_module_info["relative-directory"] = files_per_dir.first;
- tdi_module_info["name"] = file_set->GetName();
- tdi_module_info["type"] = file_set->GetType();
- tdi_module_info["visibility"] =
- std::string(cmFileSetVisibilityToName(file_set->GetVisibility()));
- tdi_module_info["destination"] = fs_dest;
- }
- }
- }
-
- tdi["config"] = config;
-
- // Add information about the export sets that this target is a member of.
- Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue;
- std::string export_name = this->GeneratorTarget->GetExportName();
-
- cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr;
- for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) {
- if (auto const* bmig =
- dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) {
- if (bmig->GetTarget() == this->GeneratorTarget) {
- bmi_gen = bmig;
- continue;
- }
- }
- }
- if (bmi_gen) {
- Json::Value tdi_bmi_info = Json::objectValue;
-
- tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions();
- tdi_bmi_info["destination"] = bmi_gen->GetDestination(config);
- const char* msg_level = "";
- switch (bmi_gen->GetMessageLevel()) {
- case cmInstallGenerator::MessageDefault:
- break;
- case cmInstallGenerator::MessageAlways:
- msg_level = "MESSAGE_ALWAYS";
- break;
- case cmInstallGenerator::MessageLazy:
- msg_level = "MESSAGE_LAZY";
- break;
- case cmInstallGenerator::MessageNever:
- msg_level = "MESSAGE_NEVER";
- break;
- }
- tdi_bmi_info["message-level"] = msg_level;
- tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config);
-
- tdi["bmi-installation"] = tdi_bmi_info;
- } else {
- tdi["bmi-installation"] = Json::nullValue;
- }
-
- auto const& all_install_exports =
- this->GetGlobalGenerator()->GetExportSets();
- for (auto const& exp : all_install_exports) {
- // Ignore exports sets which are not for this target.
- auto const& targets = exp.second.GetTargetExports();
- auto tgt_export =
- std::find_if(targets.begin(), targets.end(),
- [this](std::unique_ptr<cmTargetExport> const& te) {
- return te->Target == this->GeneratorTarget;
- });
- if (tgt_export == targets.end()) {
- continue;
- }
-
- auto const* installs = exp.second.GetInstallations();
- for (auto const* install : *installs) {
- Json::Value tdi_export_info = Json::objectValue;
-
- auto const& ns = install->GetNamespace();
- auto const& dest = install->GetDestination();
- auto const& cxxm_dir = install->GetCxxModuleDirectory();
- auto const& export_prefix = install->GetTempDir();
-
- tdi_export_info["namespace"] = ns;
- tdi_export_info["export-name"] = export_name;
- tdi_export_info["destination"] = dest;
- tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
- tdi_export_info["export-prefix"] = export_prefix;
- tdi_export_info["install"] = true;
-
- tdi_exports.append(tdi_export_info);
- }
- }
-
- auto const& all_build_exports =
- this->GetMakefile()->GetExportBuildFileGenerators();
- for (auto const& exp : all_build_exports) {
- std::vector<std::string> targets;
- exp->GetTargets(targets);
+ cmDyndepGeneratorCallbacks cb;
+ cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) {
+ return this->GetObjectFilePath(sf, cnf);
+ };
- // Ignore exports sets which are not for this target.
- auto const& name = this->GeneratorTarget->GetName();
- bool has_current_target =
- std::any_of(targets.begin(), targets.end(),
- [name](std::string const& tname) { return tname == name; });
- if (!has_current_target) {
- continue;
- }
-
- Json::Value tdi_export_info = Json::objectValue;
-
- auto const& ns = exp->GetNamespace();
- auto const& main_fn = exp->GetMainExportFileName();
- auto const& cxxm_dir = exp->GetCxxModuleDirectory();
- auto dest = cmsys::SystemTools::GetParentDirectory(main_fn);
- auto const& export_prefix =
- cmSystemTools::GetFilenamePath(exp->GetMainExportFileName());
-
- tdi_export_info["namespace"] = ns;
- tdi_export_info["export-name"] = export_name;
- tdi_export_info["destination"] = dest;
- tdi_export_info["cxx-module-info-dir"] = cxxm_dir;
- tdi_export_info["export-prefix"] = export_prefix;
- tdi_export_info["install"] = false;
-
- tdi_exports.append(tdi_export_info);
- }
+#if !defined(CMAKE_BOOTSTRAP)
+ cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget,
+ config, cb);
+#endif
std::string const tdin = this->GetTargetDependInfoPath(lang, config);
cmGeneratedFileStream tdif(tdin);
@@ -1998,7 +1814,8 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string cmdLine = this->GetLocalGenerator()->BuildCommandLine(
compileCmds, outputConfig, outputConfig);
- this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName);
+ this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName,
+ objectFileName);
}
void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config)
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 4b4cf8d..8bf7986 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -63,19 +63,22 @@ protected:
cmMakefile* GetMakefile() const { return this->Makefile; }
+ enum class WithScanning
+ {
+ No,
+ Yes,
+ };
std::string LanguageCompilerRule(const std::string& lang,
- const std::string& config) const;
+ const std::string& config,
+ WithScanning withScanning) 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);
@@ -131,6 +134,11 @@ protected:
std::string GetPreprocessedFilePath(cmSourceFile const* source,
const std::string& config) const;
+ /// @return the clang-tidy replacements file path for the given @a source.
+ std::string GetClangTidyReplacementsFilePath(
+ const std::string& directory, 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;
@@ -150,6 +158,8 @@ protected:
const std::string& config);
void WriteCompileRule(const std::string& language,
const std::string& config);
+ void WriteCompileRule(const std::string& language, const std::string& config,
+ WithScanning withScanning);
void WriteObjectBuildStatements(const std::string& config,
const std::string& fileConfig,
bool firstForConfig);
@@ -163,6 +173,9 @@ protected:
void EmitSwiftDependencyInfo(cmSourceFile const* source,
const std::string& config);
+ void GenerateSwiftOutputFileMap(const std::string& config,
+ std::string& flags);
+
void ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index 299ab3a..6c54e01 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -154,7 +154,7 @@ std::string cmOutputConverter::MaybeRelativeToCurBinDir(
}
std::string cmOutputConverter::ConvertToOutputForExisting(
- const std::string& remote, OutputFormat format) const
+ const std::string& remote, OutputFormat format, bool useWatcomQuote) const
{
#ifdef _WIN32
// Cache the Short Paths since we only convert the same few paths anyway and
@@ -181,25 +181,27 @@ std::string cmOutputConverter::ConvertToOutputForExisting(
return tmp;
}();
- return this->ConvertToOutputFormat(shortPath, format);
+ return this->ConvertToOutputFormat(shortPath, format, useWatcomQuote);
}
#endif
// Otherwise, perform standard conversion.
- return this->ConvertToOutputFormat(remote, format);
+ return this->ConvertToOutputFormat(remote, format, useWatcomQuote);
}
std::string cmOutputConverter::ConvertToOutputFormat(cm::string_view source,
- OutputFormat output) const
+ OutputFormat format,
+ bool useWatcomQuote) const
{
std::string result(source);
// Convert it to an output path.
- if (output == SHELL || output == WATCOMQUOTE || output == NINJAMULTI) {
+ if (format == SHELL || format == 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, false, true);
+ result = this->EscapeForShell(result, true, false, useWatcomQuote,
+ format == NINJAMULTI);
+ } else if (format == RESPONSE) {
+ result =
+ this->EscapeForShell(result, false, false, useWatcomQuote, false, true);
}
return result;
}
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 6e1bfe3..2717bdd 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -35,17 +35,18 @@ public:
enum OutputFormat
{
SHELL,
- WATCOMQUOTE,
NINJAMULTI,
RESPONSE
};
std::string ConvertToOutputFormat(cm::string_view source,
- OutputFormat output) const;
+ OutputFormat output,
+ bool useWatcomQuote = false) 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;
+ OutputFormat format = SHELL,
+ bool useWatcomQuote = false) const;
void SetLinkScriptShell(bool linkScriptShell);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 4643868..fa24f57 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -431,7 +431,10 @@ class cmMakefile;
SELECT(POLICY, CMP0142, \
"The Xcode generator does not append per-config suffixes to " \
"library search paths.", \
- 3, 25, 0, cmPolicies::WARN)
+ 3, 25, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0143, \
+ "Global property USE_FOLDERS treated as ON by default", 3, 26, 0, \
+ cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 249fe2d..4d1ccfe 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -34,6 +34,15 @@ bool cmProjectCommand(std::vector<std::string> const& args,
}
cmMakefile& mf = status.GetMakefile();
+ if (mf.IsRootMakefile() &&
+ !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+ mf.IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ "cmake_minimum_required() should be called prior to this top-level "
+ "project() call. Please see the cmake-commands(7) manual for usage "
+ "documentation of both commands.");
+ }
+
if (!IncludeByVariable(status, "CMAKE_PROJECT_INCLUDE_BEFORE")) {
return false;
}
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 96649ab..66e591e 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -970,8 +970,7 @@ bool cmQtAutoGenInitializer::InitScanFiles()
uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s),
uiHeaderFilePath);
- this->Uic.UiHeaders.emplace_back(
- std::make_pair(uiHeader, uiHeaderGenex));
+ this->Uic.UiHeaders.emplace_back(uiHeader, uiHeaderGenex);
} else {
// Register skipped .ui file
this->Uic.SkipUi.insert(fullPath);
@@ -2095,7 +2094,7 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
// Evaluate generator expression
{
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
- cmGeneratorExpression ge(lfbt);
+ cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
genVars.Executable = cge->Evaluate(this->LocalGen, "");
}
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 4753e61..b7af859 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -1756,7 +1756,7 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping,
if (this->MocConst().SettingsChanged) {
if (reason != nullptr) {
*reason = cmStrCat("Generating ", this->MessagePath(outputFile),
- ", because the uic settings changed, from ",
+ ", because the moc settings changed, from ",
this->MessagePath(sourceFile));
}
return true;
@@ -1981,6 +1981,9 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
std::string const& sourceFile = this->Mapping->SourceFile->FileName;
std::string const& outputFile = this->Mapping->OutputFile;
+ // Remove output file in case the case of the source file has changed
+ cmSystemTools::RemoveFile(outputFile);
+
// Compose moc command
std::vector<std::string> cmd;
{
diff --git a/Source/cmRange.h b/Source/cmRange.h
index 30af7d2..85cb8ea 100644
--- a/Source/cmRange.h
+++ b/Source/cmRange.h
@@ -76,9 +76,9 @@ 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 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&;
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index b63d11c..638bb42 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -119,11 +119,6 @@ std::string cmRulePlaceholderExpander::ExpandVariable(
return this->ReplaceValues->SwiftModuleName;
}
}
- if (this->ReplaceValues->SwiftOutputFileMap) {
- if (variable == "SWIFT_OUTPUT_FILE_MAP") {
- return this->ReplaceValues->SwiftOutputFileMap;
- }
- }
if (this->ReplaceValues->SwiftSources) {
if (variable == "SWIFT_SOURCES") {
return this->ReplaceValues->SwiftSources;
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 23ec405..5d1f199 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -64,7 +64,7 @@ public:
const char* SwiftLibraryName = nullptr;
const char* SwiftModule = nullptr;
const char* SwiftModuleName = nullptr;
- const char* SwiftOutputFileMap = nullptr;
+ const char* SwiftOutputFileMapOption = nullptr;
const char* SwiftSources = nullptr;
const char* ISPCHeader = nullptr;
const char* CudaCompileMode = nullptr;
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index 6c53b85..d5f6f0d 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -179,12 +179,27 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
cmValue arch =
this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
if (cmNonempty(arch)) {
+ std::string archNoUnknown = *arch;
+ auto unknownAtPos = archNoUnknown.find("-unknown-");
+ bool foundUnknown = unknownAtPos != std::string::npos;
+ if (foundUnknown) {
+ // Replace "-unknown-" with "-".
+ archNoUnknown.replace(unknownAtPos, 9, "-");
+ }
if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
this->FC->Makefile->IsDefinitionSet(
"CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
+ if (foundUnknown) {
+ this->AddPathInternal(cmStrCat('/', archNoUnknown, dir, subdir),
+ cmStrCat('/', archNoUnknown, prefix), base);
+ }
this->AddPathInternal(cmStrCat('/', *arch, dir, subdir),
cmStrCat('/', *arch, prefix), base);
} else {
+ if (foundUnknown) {
+ this->AddPathInternal(cmStrCat(dir, subdir, '/', archNoUnknown),
+ prefix, base);
+ }
this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix,
base);
}
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 521cf63..de1e3b0 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -619,10 +619,9 @@ bool HandleSource(cmSourceFile* sf, const std::string& propertyName,
if (propertyName == "GENERATED") {
SetPropertyCommand::PropertyOp op = (remove)
? SetPropertyCommand::PropertyOp::Remove
- : (appendAsString)
- ? SetPropertyCommand::PropertyOp::AppendAsString
- : (appendMode) ? SetPropertyCommand::PropertyOp::Append
- : SetPropertyCommand::PropertyOp::Set;
+ : (appendAsString) ? SetPropertyCommand::PropertyOp::AppendAsString
+ : (appendMode) ? SetPropertyCommand::PropertyOp::Append
+ : SetPropertyCommand::PropertyOp::Set;
return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED(
sf, propertyValue, op);
}
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index e54ccfc..f12f91f 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -786,6 +786,8 @@ std::string cmState::ModeToString(cmState::Mode mode)
return "CTEST";
case CPack:
return "CPACK";
+ case Help:
+ return "HELP";
case Unknown:
return "UNKNOWN";
}
diff --git a/Source/cmState.h b/Source/cmState.h
index 2d0c521..9a17b22 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -53,6 +53,7 @@ public:
FindPackage,
CTest,
CPack,
+ Help
};
enum class ProjectKind
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index cb5f11f..e230702 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -301,14 +301,6 @@ void cmStateSnapshot::SetDefaultDefinitions()
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");
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index f73c854..66bf383 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -203,17 +203,45 @@ cmAlphaNum::cmAlphaNum(double val)
MakeDigits(this->View_, this->Digits_, "%g", val);
}
-std::string cmCatViews(std::initializer_list<cm::string_view> views)
+std::string cmCatViews(
+ std::initializer_list<std::pair<cm::string_view, std::string*>> views)
{
- std::size_t total_size = 0;
- for (cm::string_view const& view : views) {
- total_size += view.size();
+ std::size_t totalSize = 0;
+ std::string* rvalueString = nullptr;
+ std::size_t rvalueStringLength = 0;
+ std::size_t rvalueStringOffset = 0;
+ for (auto const& view : views) {
+ // Find the rvalue string with the largest capacity.
+ if (view.second &&
+ (!rvalueString ||
+ view.second->capacity() > rvalueString->capacity())) {
+ rvalueString = view.second;
+ rvalueStringLength = rvalueString->length();
+ rvalueStringOffset = totalSize;
+ }
+ totalSize += view.first.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);
+ std::string result;
+ std::string::size_type initialLen = 0;
+ if (rvalueString && rvalueString->capacity() >= totalSize) {
+ result = std::move(*rvalueString);
+ } else {
+ rvalueString = nullptr;
+ }
+ result.resize(totalSize);
+ if (rvalueString && rvalueStringOffset > 0) {
+ std::copy_backward(result.begin(), result.begin() + rvalueStringLength,
+ result.begin() + rvalueStringOffset +
+ rvalueStringLength);
+ }
+ std::string::iterator sit = result.begin() + initialLen;
+ for (auto const& view : views) {
+ if (rvalueString && view.second == rvalueString) {
+ sit += rvalueStringLength;
+ } else {
+ sit = std::copy_n(view.first.data(), view.first.size(), sit);
+ }
}
return result;
}
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 83938bc..9ea7491 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -146,7 +146,8 @@ std::vector<std::string> cmExpandedLists(InputIt first, InputIt last)
}
/** Concatenate string pieces into a single string. */
-std::string cmCatViews(std::initializer_list<cm::string_view> views);
+std::string cmCatViews(
+ std::initializer_list<std::pair<cm::string_view, std::string*>> views);
/** Utility class for cmStrCat. */
class cmAlphaNum
@@ -160,6 +161,10 @@ public:
: View_(str)
{
}
+ cmAlphaNum(std::string&& str)
+ : RValueString_(&str)
+ {
+ }
cmAlphaNum(const char* str)
: View_(str)
{
@@ -182,20 +187,34 @@ public:
{
}
- cm::string_view View() const { return this->View_; }
+ cm::string_view View() const
+ {
+ if (this->RValueString_) {
+ return *this->RValueString_;
+ }
+ return this->View_;
+ }
+
+ std::string* RValueString() const { return this->RValueString_; }
private:
+ std::string* RValueString_ = nullptr;
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)
+template <typename A, typename B, typename... AV>
+inline std::string cmStrCat(A&& a, B&& b, AV&&... args)
{
- return cmCatViews(
- { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... });
+ static auto const makePair =
+ [](const cmAlphaNum& arg) -> std::pair<cm::string_view, std::string*> {
+ return { arg.View(), arg.RValueString() };
+ };
+
+ return cmCatViews({ makePair(std::forward<A>(a)),
+ makePair(std::forward<B>(b)),
+ makePair(std::forward<AV>(args))... });
}
/** Joins wrapped elements of a range with separator into a single string. */
@@ -206,8 +225,13 @@ std::string cmWrap(cm::string_view prefix, Range const& rng,
if (rng.empty()) {
return std::string();
}
- return cmCatViews(
- { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix });
+ return cmCatViews({ { prefix, nullptr },
+ { cmJoin(rng,
+ cmCatViews({ { suffix, nullptr },
+ { sep, nullptr },
+ { prefix, nullptr } })),
+ nullptr },
+ { suffix, nullptr } });
}
/** Joins wrapped elements of a range with separator into a single string. */
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index c12d1fe..5a64588 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -9,7 +9,6 @@
#include <cctype>
#include <cstdio>
#include <cstdlib>
-#include <initializer_list>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -950,9 +949,9 @@ struct Args : cmRange<typename std::vector<std::string>::const_iterator>
class json_error : public std::runtime_error
{
public:
- json_error(std::initializer_list<cm::string_view> message,
+ json_error(const std::string& message,
cm::optional<Args> errorPath = cm::nullopt)
- : std::runtime_error(cmCatViews(message))
+ : std::runtime_error(message)
, ErrorPath{
std::move(errorPath) // NOLINT(performance-move-const-arg)
}
@@ -964,7 +963,7 @@ public:
const std::string& Args::PopFront(cm::string_view error)
{
if (this->empty()) {
- throw json_error({ error });
+ throw json_error(std::string(error));
}
const std::string& res = *this->begin();
this->advance(1);
@@ -974,7 +973,7 @@ const std::string& Args::PopFront(cm::string_view error)
const std::string& Args::PopBack(cm::string_view error)
{
if (this->empty()) {
- throw json_error({ error });
+ throw json_error(std::string(error));
}
const std::string& res = *(this->end() - 1);
this->retreat(1);
@@ -999,7 +998,7 @@ cm::string_view JsonTypeToString(Json::ValueType type)
case Json::ValueType::objectValue:
return "OBJECT"_s;
}
- throw json_error({ "invalid JSON type found"_s });
+ throw json_error("invalid JSON type found");
}
int ParseIndex(
@@ -1008,14 +1007,14 @@ int ParseIndex(
{
unsigned long lindex;
if (!cmStrToULong(str, &lindex)) {
- throw json_error({ "expected an array index, got: '"_s, str, "'"_s },
+ throw json_error(cmStrCat("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 than "_s, sizeStr.View(),
- " got '"_s, str, "'"_s },
+ throw json_error(cmStrCat("expected an index less than "_s, sizeStr.View(),
+ " got '"_s, str, "'"_s),
progress);
}
return index;
@@ -1036,16 +1035,16 @@ Json::Value& ResolvePath(Json::Value& json, Args path)
} else if (search->isObject()) {
if (!search->isMember(field)) {
const auto progressStr = cmJoin(progress, " "_s);
- throw json_error({ "member '"_s, progressStr, "' not found"_s },
+ throw json_error(cmStrCat("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()) },
+ cmStrCat("invalid path '"_s, progressStr,
+ "', need element of OBJECT or ARRAY type to lookup '"_s,
+ field, "' got "_s, JsonTypeToString(search->type())),
progress);
}
}
@@ -1061,7 +1060,7 @@ Json::Value ReadJson(const std::string& jsonstr)
std::string error;
if (!jsonReader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(),
&json, &error)) {
- throw json_error({ "failed parsing json string: "_s, error });
+ throw json_error(cmStrCat("failed parsing json string: "_s, error));
}
return json;
}
@@ -1101,9 +1100,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
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, TYPE, MEMBER, LENGTH, REMOVE, SET, "
- " EQUAL"_s });
+ cmStrCat("got an invalid mode '"_s, mode,
+ "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, "
+ " EQUAL"_s));
}
const auto& jsonstr = args.PopFront("missing json string argument"_s);
@@ -1127,10 +1126,11 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
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);
+ throw json_error(
+ cmStrCat("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());
@@ -1140,9 +1140,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
} 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()) },
+ throw json_error(cmStrCat("LENGTH needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type())),
args);
}
@@ -1165,9 +1165,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
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()) },
+ throw json_error(cmStrCat("REMOVE needs to be called with an "
+ "element of type ARRAY or OBJECT, got "_s,
+ JsonTypeToString(value.type())),
args);
}
makefile.AddDefinition(*outputVariable, WriteJson(json));
@@ -1189,9 +1189,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
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()) });
+ throw json_error(cmStrCat("SET needs to be called with an "
+ "element of type OBJECT or ARRAY, got "_s,
+ JsonTypeToString(value.type())));
}
makefile.AddDefinition(*outputVariable, WriteJson(json));
@@ -1207,7 +1207,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
if (outputVariable && e.ErrorPath) {
const auto errorPath = cmJoin(*e.ErrorPath, "-");
makefile.AddDefinition(*outputVariable,
- cmCatViews({ errorPath, "-NOTFOUND"_s }));
+ cmStrCat(errorPath, "-NOTFOUND"_s));
} else if (outputVariable) {
makefile.AddDefinition(*outputVariable, "NOTFOUND"_s);
}
@@ -1215,7 +1215,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments,
if (errorVariable) {
makefile.AddDefinition(*errorVariable, e.what());
} else {
- status.SetError(cmCatViews({ "sub-command JSON "_s, e.what(), "."_s }));
+ status.SetError(cmStrCat("sub-command JSON "_s, e.what(), "."_s));
success = false;
}
}
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index ee74908..0b29b0d 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1111,16 +1111,9 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
}
#endif
-bool cmSystemTools::CopySingleFile(const std::string& oldname,
- const std::string& newname)
-{
- return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) ==
- CopyResult::Success;
-}
-
cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
std::string const& oldname, std::string const& newname, CopyWhen when,
- std::string* err)
+ CopyInputRecent inputRecent, std::string* err)
{
switch (when) {
case CopyWhen::Always:
@@ -1140,23 +1133,50 @@ cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
return CopyResult::Success;
}
- cmsys::Status status;
+ cmsys::SystemTools::CopyStatus status;
status = cmsys::SystemTools::CloneFileContent(oldname, newname);
if (!status) {
// if cloning did not succeed, fall back to blockwise copy
+#ifdef _WIN32
+ if (inputRecent == CopyInputRecent::Yes) {
+ // Windows sometimes locks a file immediately after creation.
+ // Retry a few times.
+ WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
+ while ((status =
+ cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname),
+ status.Path == cmsys::SystemTools::CopyStatus::SourcePath &&
+ status.GetPOSIX() == EACCES && --retry.Count)) {
+ cmSystemTools::Delay(retry.Delay);
+ }
+ } else {
+ status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
+ }
+#else
+ static_cast<void>(inputRecent);
status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
+#endif
}
if (!status) {
if (err) {
*err = status.GetString();
+ switch (status.Path) {
+ case cmsys::SystemTools::CopyStatus::SourcePath:
+ *err = cmStrCat(*err, " (input)");
+ break;
+ case cmsys::SystemTools::CopyStatus::DestPath:
+ *err = cmStrCat(*err, " (output)");
+ break;
+ default:
+ break;
+ }
}
return CopyResult::Failure;
}
if (perms) {
- status = SystemTools::SetPermissions(newname, perm);
- if (!status) {
+ perms = SystemTools::SetPermissions(newname, perm);
+ if (!perms) {
if (err) {
- *err = status.GetString();
+ *err = cmStrCat(perms.GetString(), " (output)");
}
return CopyResult::Failure;
}
@@ -3024,7 +3044,7 @@ static cm::optional<bool> SetRPathELF(std::string const& file,
{
auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
const std::string& inRPath,
- const char* /*se_name*/, std::string *
+ const char* /*se_name*/, std::string*
/*emsg*/) -> bool {
if (inRPath != newRPath) {
outRPath = newRPath;
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 87b354c..09f2bf0 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -149,6 +149,11 @@ public:
Always,
OnlyIfDifferent,
};
+ enum class CopyInputRecent
+ {
+ No,
+ Yes,
+ };
enum class CopyResult
{
Success,
@@ -177,10 +182,9 @@ public:
const mode_t* mode = nullptr);
/** Copy a file. */
- static bool CopySingleFile(const std::string& oldname,
- const std::string& newname);
static CopyResult CopySingleFile(std::string const& oldname,
std::string const& newname, CopyWhen when,
+ CopyInputRecent inputRecent,
std::string* err = nullptr);
enum class Replace
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 874195b..debf593 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -4,7 +4,6 @@
#include <algorithm>
#include <cassert>
-#include <cstring>
#include <initializer_list>
#include <iterator>
#include <map>
@@ -213,9 +212,16 @@ struct FileSetType
FileSetEntries SelfEntries;
FileSetEntries InterfaceEntries;
+ enum class Action
+ {
+ Set,
+ Append,
+ };
+
template <typename ValueType>
bool WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
- const std::string& prop, ValueType value, bool clear);
+ const std::string& prop, ValueType value,
+ Action action);
std::pair<bool, cmValue> ReadProperties(cmTarget const* tgt,
cmTargetInternals const* impl,
const std::string& prop) const;
@@ -223,6 +229,50 @@ struct FileSetType
void AddFileSet(const std::string& name, cmFileSetVisibility vis,
cmListFileBacktrace bt);
};
+
+struct UsageRequirementProperty
+{
+ enum class AppendEmpty
+ {
+ Yes,
+ No,
+ };
+
+ UsageRequirementProperty(cm::static_string_view name,
+ AppendEmpty appendEmpty = AppendEmpty::No)
+ : Name(name)
+ , AppendBehavior(appendEmpty)
+ {
+ }
+
+ void CopyFromDirectory(cmBTStringRange directoryEntries)
+ {
+ return cm::append(this->Entries, directoryEntries);
+ }
+
+ enum class Action
+ {
+ Set,
+ Prepend,
+ Append,
+ };
+
+ template <typename ValueType>
+ bool Write(cmTargetInternals const* impl,
+ cm::optional<cmListFileBacktrace> const& bt,
+ const std::string& prop, ValueType value, Action action);
+ template <typename ValueType>
+ void WriteDirect(cmTargetInternals const* impl,
+ cm::optional<cmListFileBacktrace> const& bt,
+ ValueType value, Action action);
+ void WriteDirect(BT<std::string> value, Action action);
+ std::pair<bool, cmValue> Read(const std::string& prop) const;
+
+ cm::static_string_view const Name;
+ AppendEmpty const AppendBehavior;
+
+ std::vector<BT<std::string>> Entries;
+};
}
class cmTargetInternals
@@ -252,25 +302,26 @@ public:
std::set<std::string> SystemIncludeDirectories;
cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
std::map<std::string, BTs<std::string>> LanguageStandardProperties;
- std::vector<BT<std::string>> IncludeDirectoriesEntries;
std::map<cmTargetExport const*, std::vector<std::string>>
InstallIncludeDirectoriesEntries;
- std::vector<BT<std::string>> CompileOptionsEntries;
- std::vector<BT<std::string>> CompileFeaturesEntries;
- std::vector<BT<std::string>> CompileDefinitionsEntries;
- std::vector<BT<std::string>> PrecompileHeadersEntries;
- std::vector<BT<std::string>> SourceEntries;
- std::vector<BT<std::string>> LinkOptionsEntries;
- std::vector<BT<std::string>> LinkDirectoriesEntries;
- std::vector<BT<std::string>> LinkImplementationPropertyEntries;
- std::vector<BT<std::string>> LinkInterfacePropertyEntries;
- std::vector<BT<std::string>> LinkInterfaceDirectPropertyEntries;
- std::vector<BT<std::string>> LinkInterfaceDirectExcludePropertyEntries;
std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
TLLCommands;
std::map<std::string, cmFileSet> FileSets;
cmListFileBacktrace Backtrace;
+ UsageRequirementProperty IncludeDirectories;
+ UsageRequirementProperty CompileOptions;
+ UsageRequirementProperty CompileFeatures;
+ UsageRequirementProperty CompileDefinitions;
+ UsageRequirementProperty PrecompileHeaders;
+ UsageRequirementProperty Sources;
+ UsageRequirementProperty LinkOptions;
+ UsageRequirementProperty LinkDirectories;
+ UsageRequirementProperty LinkLibraries;
+ UsageRequirementProperty InterfaceLinkLibraries;
+ UsageRequirementProperty InterfaceLinkLibrariesDirect;
+ UsageRequirementProperty InterfaceLinkLibrariesDirectExclude;
+
FileSetType HeadersFileSets;
FileSetType CxxModulesFileSets;
FileSetType CxxModuleHeadersFileSets;
@@ -285,11 +336,13 @@ public:
template <typename ValueType>
void AddDirectoryToFileSet(cmTarget* self, std::string const& fileSetName,
ValueType value, cm::string_view fileSetType,
- cm::string_view description, bool clear);
+ cm::string_view description,
+ FileSetType::Action action);
template <typename ValueType>
void AddPathToFileSet(cmTarget* self, std::string const& fileSetName,
ValueType value, cm::string_view fileSetType,
- cm::string_view description, bool clear);
+ cm::string_view description,
+ FileSetType::Action action);
cmValue GetFileSetDirectories(cmTarget const* self,
std::string const& fileSetName,
cm::string_view fileSetType) const;
@@ -304,7 +357,20 @@ public:
};
cmTargetInternals::cmTargetInternals()
- : HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s,
+ : IncludeDirectories("INCLUDE_DIRECTORIES"_s)
+ , CompileOptions("COMPILE_OPTIONS"_s)
+ , CompileFeatures("COMPILE_FEATURES"_s)
+ , CompileDefinitions("COMPILE_DEFINITIONS"_s)
+ , PrecompileHeaders("PRECOMPILE_HEADERS"_s)
+ , Sources("SOURCES"_s, UsageRequirementProperty::AppendEmpty::Yes)
+ , LinkOptions("LINK_OPTIONS"_s)
+ , LinkDirectories("LINK_DIRECTORIES"_s)
+ , LinkLibraries("LINK_LIBRARIES"_s)
+ , InterfaceLinkLibraries("INTERFACE_LINK_LIBRARIES"_s)
+ , InterfaceLinkLibrariesDirect("INTERFACE_LINK_LIBRARIES_DIRECT"_s)
+ , InterfaceLinkLibrariesDirectExclude(
+ "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s)
+ , HeadersFileSets("HEADERS"_s, "HEADER_DIRS"_s, "HEADER_SET"_s,
"HEADER_DIRS_"_s, "HEADER_SET_"_s, "Header"_s,
"The default header set"_s, "Header set"_s,
FileSetEntries("HEADER_SETS"_s),
@@ -328,17 +394,17 @@ cmTargetInternals::cmTargetInternals()
template <typename ValueType>
bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
const std::string& prop, ValueType value,
- bool clear)
+ Action action)
{
if (prop == this->DefaultDirectoryProperty) {
impl->AddDirectoryToFileSet(tgt, std::string(this->TypeName), value,
this->TypeName, this->DefaultDescription,
- clear);
+ action);
return true;
}
if (prop == this->DefaultPathProperty) {
impl->AddPathToFileSet(tgt, std::string(this->TypeName), value,
- this->TypeName, this->DefaultDescription, clear);
+ this->TypeName, this->DefaultDescription, action);
return true;
}
if (cmHasPrefix(prop, this->DirectoryPrefix)) {
@@ -350,7 +416,8 @@ bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
} else {
impl->AddDirectoryToFileSet(
tgt, fileSetName, value, this->TypeName,
- cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear);
+ cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""),
+ action);
}
return true;
}
@@ -363,7 +430,8 @@ bool FileSetType::WriteProperties(cmTarget* tgt, cmTargetInternals* impl,
} else {
impl->AddPathToFileSet(
tgt, fileSetName, value, this->TypeName,
- cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""), clear);
+ cmStrCat(this->ArbitraryDescription, " \"", fileSetName, "\""),
+ action);
}
return true;
}
@@ -433,6 +501,67 @@ void FileSetType::AddFileSet(const std::string& name, cmFileSetVisibility vis,
}
}
+template <typename ValueType>
+bool UsageRequirementProperty::Write(
+ cmTargetInternals const* impl, cm::optional<cmListFileBacktrace> const& bt,
+ const std::string& prop, ValueType value, Action action)
+{
+ if (prop == this->Name) {
+ this->WriteDirect(impl, bt, value, action);
+ return true;
+ }
+ return false;
+}
+
+template <typename ValueType>
+void UsageRequirementProperty::WriteDirect(
+ cmTargetInternals const* impl, cm::optional<cmListFileBacktrace> const& bt,
+ ValueType value, Action action)
+{
+ if (action == Action::Set) {
+ this->Entries.clear();
+ }
+ if (value) {
+ cmListFileBacktrace lfbt = impl->GetBacktrace(bt);
+ if (action == Action::Prepend) {
+ this->Entries.emplace(this->Entries.begin(), value, lfbt);
+ } else if (action == Action::Set || cmNonempty(value) ||
+ this->AppendBehavior == AppendEmpty::Yes) {
+ this->Entries.emplace_back(value, lfbt);
+ }
+ }
+}
+
+void UsageRequirementProperty::WriteDirect(BT<std::string> value,
+ Action action)
+{
+ if (action == Action::Set) {
+ this->Entries.clear();
+ }
+ if (action == Action::Prepend) {
+ this->Entries.emplace(this->Entries.begin(), std::move(value));
+ } else {
+ this->Entries.emplace_back(std::move(value));
+ }
+}
+
+std::pair<bool, cmValue> UsageRequirementProperty::Read(
+ const std::string& prop) const
+{
+ bool did_read = false;
+ cmValue value = nullptr;
+ if (prop == this->Name) {
+ if (!this->Entries.empty()) {
+ // Storage to back the returned `cmValue`.
+ static std::string output;
+ output = cmJoin(this->Entries, ";");
+ value = cmValue(output);
+ }
+ did_read = true;
+ }
+ return { did_read, value };
+}
+
namespace {
#define SETUP_COMMON_LANGUAGE_PROPERTIES(lang) \
initProp(#lang "_COMPILER_LAUNCHER"); \
@@ -501,121 +630,186 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
// 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);
- SETUP_COMMON_LANGUAGE_PROPERTIES(HIP);
-
+ // Compilation properties
+ initProp("INTERPROCEDURAL_OPTIMIZATION");
+ // initProp("INTERPROCEDURAL_OPTIMIZATION_<CONFIG>"); (per-config block)
+ initProp("NO_SYSTEM_FROM_IMPORTED");
+ initProp("VISIBILITY_INLINES_HIDDEN");
+ initProp("COMPILE_WARNING_AS_ERROR");
+ // -- Features
+ // ---- PCH
+ initProp("DISABLE_PRECOMPILE_HEADERS");
+ initPropValue("PCH_WARN_INVALID", "ON");
+ initPropValue("PCH_INSTANTIATE_TEMPLATES", "ON");
+ // -- Platforms
+ // ---- Android
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("ANDROID_JAVA_SOURCE_DIR");
+ initProp("ANDROID_STL_TYPE");
+ // ---- macOS
+ initProp("OSX_ARCHITECTURES");
+ // ---- Windows
+ initProp("MSVC_DEBUG_INFORMATION_FORMAT");
+ initProp("MSVC_RUNTIME_LIBRARY");
+ initProp("VS_JUST_MY_CODE_DEBUGGING");
+ // ---- OpenWatcom
+ initProp("WATCOM_RUNTIME_LIBRARY");
+ // -- Language
+ // ---- C
+ SETUP_COMMON_LANGUAGE_PROPERTIES(C);
+ // ---- C++
+ SETUP_COMMON_LANGUAGE_PROPERTIES(CXX);
+ // ---- CUDA
+ SETUP_COMMON_LANGUAGE_PROPERTIES(CUDA);
+ initProp("CUDA_SEPARABLE_COMPILATION");
+ initProp("CUDA_ARCHITECTURES");
+ // ---- Fortran
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");
+ // ---- HIP
+ SETUP_COMMON_LANGUAGE_PROPERTIES(HIP);
+ initProp("HIP_ARCHITECTURES");
+ // ---- ISPC
+ initProp("ISPC_COMPILER_LAUNCHER");
+ initProp("ISPC_HEADER_DIRECTORY");
+ initPropValue("ISPC_HEADER_SUFFIX", "_ispc.h");
+ initProp("ISPC_INSTRUCTION_SETS");
+ // ---- Objective C
+ SETUP_COMMON_LANGUAGE_PROPERTIES(OBJC);
+ // ---- Objective C++
+ SETUP_COMMON_LANGUAGE_PROPERTIES(OBJCXX);
+ // ---- Swift
+ initProp("Swift_LANGUAGE_VERSION");
+ initProp("Swift_MODULE_DIRECTORY");
+ // ---- moc
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");
+ // ---- uic
+ initProp("AUTOUIC");
+ initProp("AUTOUIC_OPTIONS");
initProp("AUTOUIC_SEARCH_PATHS");
+ // ---- rcc
+ initProp("AUTORCC");
initProp("AUTORCC_OPTIONS");
- initProp("LINK_DEPENDS_NO_SHARED");
- initProp("LINK_INTERFACE_LIBRARIES");
- initProp("MSVC_DEBUG_INFORMATION_FORMAT");
- initProp("MSVC_RUNTIME_LIBRARY");
- initProp("WATCOM_RUNTIME_LIBRARY");
- initProp("WIN32_EXECUTABLE");
- initProp("MACOSX_BUNDLE");
+
+ // Linking properties
+ initProp("LINK_SEARCH_START_STATIC");
+ initProp("LINK_SEARCH_END_STATIC");
+ // -- Dependent library lookup
initProp("MACOSX_RPATH");
- initProp("NO_SYSTEM_FROM_IMPORTED");
+ // ---- Build
+ initProp("BUILD_RPATH");
+ initProp("BUILD_RPATH_USE_ORIGIN");
+ initPropValue("SKIP_BUILD_RPATH", "OFF");
+ initPropValue("BUILD_WITH_INSTALL_RPATH", "OFF");
initProp("BUILD_WITH_INSTALL_NAME_DIR");
+ // ---- Install
+ initProp("INSTALL_NAME_DIR");
+ initProp("INSTALL_REMOVE_ENVIRONMENT_RPATH");
+ initPropValue("INSTALL_RPATH", "");
+ initPropValue("INSTALL_RPATH_USE_LINK_PATH", "OFF");
+ // -- Platforms
+ // ---- Android
+ initProp("ANDROID_JAR_DIRECTORIES");
+ initProp("ANDROID_JAR_DEPENDENCIES");
+ initProp("ANDROID_NATIVE_LIB_DIRECTORIES");
+ initProp("ANDROID_NATIVE_LIB_DEPENDENCIES");
+ initProp("ANDROID_PROGUARD");
+ initProp("ANDROID_PROGUARD_CONFIG_PATH");
+ initProp("ANDROID_SECURE_PROPS_PATH");
+ // ---- iOS
+ initProp("IOS_INSTALL_COMBINED");
+ // ---- Windows
+ initProp("GNUtoMS");
+ initProp("WIN32_EXECUTABLE");
+ // -- Languages
+ // ---- C
+ initProp("C_LINKER_LAUNCHER");
+ // ---- C++
+ initProp("CXX_LINKER_LAUNCHER");
+ // ---- CUDA
+ initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
+ initProp("CUDA_RUNTIME_LIBRARY");
+ // ---- HIP
+ initProp("HIP_RUNTIME_LIBRARY");
+ // ---- Objective C
+ initProp("OBJC_LINKER_LAUNCHER");
+ // ---- Objective C++
+ initProp("OBJCXX_LINKER_LAUNCHER");
+
+ // Static analysis
+ // -- C
initProp("C_CLANG_TIDY");
+ initProp("C_CLANG_TIDY_EXPORT_FIXES_DIR");
initProp("C_CPPLINT");
initProp("C_CPPCHECK");
initProp("C_INCLUDE_WHAT_YOU_USE");
- initProp("C_LINKER_LAUNCHER");
- initProp("LINK_WHAT_YOU_USE");
+ // -- C++
initProp("CXX_CLANG_TIDY");
+ initProp("CXX_CLANG_TIDY_EXPORT_FIXES_DIR");
initProp("CXX_CPPLINT");
initProp("CXX_CPPCHECK");
initProp("CXX_INCLUDE_WHAT_YOU_USE");
- initProp("CXX_LINKER_LAUNCHER");
- initProp("CUDA_SEPARABLE_COMPILATION");
- initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
- initProp("CUDA_RUNTIME_LIBRARY");
- initProp("CUDA_ARCHITECTURES");
- initProp("HIP_RUNTIME_LIBRARY");
- initProp("HIP_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");
+ // -- Objective C
initProp("OBJC_CLANG_TIDY");
- initProp("OBJC_LINKER_LAUNCHER");
+ initProp("OBJC_CLANG_TIDY_EXPORT_FIXES_DIR");
+ // -- Objective C++
initProp("OBJCXX_CLANG_TIDY");
- initProp("OBJCXX_LINKER_LAUNCHER");
- initProp("Swift_LANGUAGE_VERSION");
- initProp("Swift_MODULE_DIRECTORY");
- initProp("VS_JUST_MY_CODE_DEBUGGING");
- initProp("VS_NO_COMPILE_BATCHING");
- initProp("DISABLE_PRECOMPILE_HEADERS");
+ initProp("OBJCXX_CLANG_TIDY_EXPORT_FIXES_DIR");
+ // -- Linking
+ initProp("LINK_WHAT_YOU_USE");
+
+ // Build graph properties
+ initProp("LINK_DEPENDS_NO_SHARED");
initProp("UNITY_BUILD");
initProp("UNITY_BUILD_UNIQUE_ID");
- initProp("OPTIMIZE_DEPENDENCIES");
- initProp("EXPORT_COMPILE_COMMANDS");
- initProp("COMPILE_WARNING_AS_ERROR");
initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
initPropValue("UNITY_BUILD_MODE", "BATCH");
- initPropValue("PCH_WARN_INVALID", "ON");
- initPropValue("PCH_INSTANTIATE_TEMPLATES", "ON");
+ initProp("OPTIMIZE_DEPENDENCIES");
+ // -- Android
+ initProp("ANDROID_ANT_ADDITIONAL_OPTIONS");
+ initProp("ANDROID_PROCESS_MAX");
+ initProp("ANDROID_SKIP_ANT_STEP");
+ // -- Autogen
+ initProp("AUTOGEN_ORIGIN_DEPENDS");
+ initProp("AUTOGEN_PARALLEL");
+ // -- moc
+ initProp("AUTOMOC_DEPEND_FILTERS");
+ // -- C++
+ initProp("CXX_SCAN_FOR_MODULES");
+ // -- Ninja
+ initProp("JOB_POOL_COMPILE");
+ initProp("JOB_POOL_LINK");
+ initProp("JOB_POOL_PRECOMPILE_HEADER");
+ // -- Visual Studio
+ initProp("VS_NO_COMPILE_BATCHING");
+
+ // Output location properties
+ initProp("ARCHIVE_OUTPUT_DIRECTORY");
+ initProp("LIBRARY_OUTPUT_DIRECTORY");
+ initProp("RUNTIME_OUTPUT_DIRECTORY");
+ initProp("PDB_OUTPUT_DIRECTORY");
+ initProp("COMPILE_PDB_OUTPUT_DIRECTORY");
+
+ // -- macOS bundle properties
+ initProp("FRAMEWORK");
+ initProp("FRAMEWORK_MULTI_CONFIG_POSTFIX");
+ initProp("MACOSX_BUNDLE");
+
+ // Usage requirement properties
+ initProp("LINK_INTERFACE_LIBRARIES");
+
+ // Metadata
+ initProp("EXPORT_COMPILE_COMMANDS");
#ifdef __APPLE__
if (this->GetGlobalGenerator()->IsXcode()) {
@@ -659,10 +853,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
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_"
+ "ARCHIVE_OUTPUT_DIRECTORY_"_s, "LIBRARY_OUTPUT_DIRECTORY_"_s,
+ "RUNTIME_OUTPUT_DIRECTORY_"_s, "PDB_OUTPUT_DIRECTORY_"_s,
+ "COMPILE_PDB_OUTPUT_DIRECTORY_"_s, "MAP_IMPORTED_CONFIG_"_s,
+ "INTERPROCEDURAL_OPTIMIZATION_"_s
};
// Collect the set of configuration types.
std::vector<std::string> configNames =
@@ -673,7 +867,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
// 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) {
+ prop != "MAP_IMPORTED_CONFIG_") {
continue;
}
std::string property = cmStrCat(prop, configUpper);
@@ -710,8 +904,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
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());
+ this->impl->IncludeDirectories.CopyFromDirectory(
+ this->impl->Makefile->GetIncludeDirectoriesEntries());
{
auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories();
@@ -719,14 +913,12 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
sysInc.end());
}
- cm::append(this->impl->CompileOptionsEntries,
- this->impl->Makefile->GetCompileOptionsEntries());
-
- cm::append(this->impl->LinkOptionsEntries,
- this->impl->Makefile->GetLinkOptionsEntries());
-
- cm::append(this->impl->LinkDirectoriesEntries,
- this->impl->Makefile->GetLinkDirectoriesEntries());
+ this->impl->CompileOptions.CopyFromDirectory(
+ this->impl->Makefile->GetCompileOptionsEntries());
+ this->impl->LinkOptions.CopyFromDirectory(
+ this->impl->Makefile->GetLinkOptionsEntries());
+ this->impl->LinkDirectories.CopyFromDirectory(
+ this->impl->Makefile->GetLinkDirectoriesEntries());
}
if (this->impl->TargetType == cmStateEnums::EXECUTABLE) {
@@ -853,7 +1045,7 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang,
const std::string& feature)
{
cmListFileBacktrace featureBacktrace;
- for (auto const& entry : this->impl->CompileFeaturesEntries) {
+ for (auto const& entry : this->impl->CompileFeatures.Entries) {
if (entry.Value == feature) {
featureBacktrace = entry.Backtrace;
break;
@@ -971,15 +1163,15 @@ void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd)
void cmTarget::AddTracedSources(std::vector<std::string> const& srcs)
{
if (!srcs.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->SourceEntries.emplace_back(cmJoin(srcs, ";"), lfbt);
+ this->impl->Sources.WriteDirect(this->impl.get(), {},
+ cmValue(cmJoin(srcs, ";")),
+ UsageRequirementProperty::Action::Append);
}
}
void cmTarget::AddSources(std::vector<std::string> const& srcs)
{
- std::string srcFiles;
- const char* sep = "";
+ std::vector<std::string> srcFiles;
for (auto filename : srcs) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
@@ -990,14 +1182,9 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
}
this->impl->Makefile->GetOrCreateSource(filename);
}
- srcFiles += sep;
- srcFiles += filename;
- sep = ";";
- }
- if (!srcFiles.empty()) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->SourceEntries.emplace_back(std::move(srcFiles), lfbt);
+ srcFiles.emplace_back(filename);
}
+ this->AddTracedSources(srcFiles);
}
std::string cmTargetInternals::ProcessSourceItemCMP0049(
@@ -1101,13 +1288,13 @@ 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(),
- BT<std::string>(src, lfbt));
+ auto const& sources = this->impl->Sources.Entries;
+ if (std::find_if(sources.begin(), sources.end(),
+ TargetPropertyEntryFinder(sfl)) == sources.end()) {
+ this->impl->Sources.WriteDirect(
+ this->impl.get(), {}, cmValue(src),
+ before ? UsageRequirementProperty::Action::Prepend
+ : UsageRequirementProperty::Action::Append);
}
if (cmGeneratorExpression::Find(src) != std::string::npos) {
return nullptr;
@@ -1335,62 +1522,62 @@ cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries(
cmBTStringRange cmTarget::GetIncludeDirectoriesEntries() const
{
- return cmMakeRange(this->impl->IncludeDirectoriesEntries);
+ return cmMakeRange(this->impl->IncludeDirectories.Entries);
}
cmBTStringRange cmTarget::GetCompileOptionsEntries() const
{
- return cmMakeRange(this->impl->CompileOptionsEntries);
+ return cmMakeRange(this->impl->CompileOptions.Entries);
}
cmBTStringRange cmTarget::GetCompileFeaturesEntries() const
{
- return cmMakeRange(this->impl->CompileFeaturesEntries);
+ return cmMakeRange(this->impl->CompileFeatures.Entries);
}
cmBTStringRange cmTarget::GetCompileDefinitionsEntries() const
{
- return cmMakeRange(this->impl->CompileDefinitionsEntries);
+ return cmMakeRange(this->impl->CompileDefinitions.Entries);
}
cmBTStringRange cmTarget::GetPrecompileHeadersEntries() const
{
- return cmMakeRange(this->impl->PrecompileHeadersEntries);
+ return cmMakeRange(this->impl->PrecompileHeaders.Entries);
}
cmBTStringRange cmTarget::GetSourceEntries() const
{
- return cmMakeRange(this->impl->SourceEntries);
+ return cmMakeRange(this->impl->Sources.Entries);
}
cmBTStringRange cmTarget::GetLinkOptionsEntries() const
{
- return cmMakeRange(this->impl->LinkOptionsEntries);
+ return cmMakeRange(this->impl->LinkOptions.Entries);
}
cmBTStringRange cmTarget::GetLinkDirectoriesEntries() const
{
- return cmMakeRange(this->impl->LinkDirectoriesEntries);
+ return cmMakeRange(this->impl->LinkDirectories.Entries);
}
cmBTStringRange cmTarget::GetLinkImplementationEntries() const
{
- return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
+ return cmMakeRange(this->impl->LinkLibraries.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceEntries() const
{
- return cmMakeRange(this->impl->LinkInterfacePropertyEntries);
+ return cmMakeRange(this->impl->InterfaceLinkLibraries.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceDirectEntries() const
{
- return cmMakeRange(this->impl->LinkInterfaceDirectPropertyEntries);
+ return cmMakeRange(this->impl->InterfaceLinkLibrariesDirect.Entries);
}
cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const
{
- return cmMakeRange(this->impl->LinkInterfaceDirectExcludePropertyEntries);
+ return cmMakeRange(this->impl->InterfaceLinkLibrariesDirectExclude.Entries);
}
cmBTStringRange cmTarget::GetHeaderSetsEntries() const
@@ -1476,26 +1663,6 @@ std::string ConvertToString<cmValue>(cmValue value)
return std::string(*value);
}
-template <typename ValueType>
-bool StringIsEmpty(ValueType const& value);
-
-template <>
-bool StringIsEmpty<const char*>(const char* const& value)
-{
- return cmValue::IsEmpty(value);
-}
-
-template <>
-bool StringIsEmpty<cmValue>(cmValue const& value)
-{
- return value.IsEmpty();
-}
-
-template <>
-bool StringIsEmpty<std::string>(std::string const& value)
-{
- return value.empty();
-}
}
template <typename ValueType>
@@ -1539,80 +1706,42 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
return;
}
- if (prop == propINCLUDE_DIRECTORIES) {
- this->impl->IncludeDirectoriesEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_OPTIONS) {
- this->impl->CompileOptionsEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_FEATURES) {
- this->impl->CompileFeaturesEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_DEFINITIONS) {
- this->impl->CompileDefinitionsEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propLINK_OPTIONS) {
- this->impl->LinkOptionsEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propLINK_DIRECTORIES) {
- this->impl->LinkDirectoriesEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkDirectoriesEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propPRECOMPILE_HEADERS) {
- this->impl->PrecompileHeadersEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propLINK_LIBRARIES) {
- this->impl->LinkImplementationPropertyEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES) {
- this->impl->LinkInterfacePropertyEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
- this->impl->LinkInterfaceDirectPropertyEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
- this->impl->LinkInterfaceDirectExcludePropertyEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
- lfbt);
+ UsageRequirementProperty* usageRequirements[] = {
+ &this->impl->IncludeDirectories,
+ &this->impl->CompileOptions,
+ &this->impl->CompileFeatures,
+ &this->impl->CompileDefinitions,
+ &this->impl->PrecompileHeaders,
+ &this->impl->Sources,
+ &this->impl->LinkOptions,
+ &this->impl->LinkDirectories,
+ &this->impl->LinkLibraries,
+ &this->impl->InterfaceLinkLibraries,
+ &this->impl->InterfaceLinkLibrariesDirect,
+ &this->impl->InterfaceLinkLibrariesDirectExclude,
+ };
+
+ for (auto* usageRequirement : usageRequirements) {
+ if (usageRequirement->Write(this->impl.get(), {}, prop, value,
+ UsageRequirementProperty::Action::Set)) {
+ return;
}
- } else if (prop == propSOURCES) {
- this->impl->SourceEntries.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace();
- this->impl->SourceEntries.emplace_back(value, lfbt);
+ }
+
+ FileSetType* fileSetTypes[] = {
+ &this->impl->HeadersFileSets,
+ &this->impl->CxxModulesFileSets,
+ &this->impl->CxxModuleHeadersFileSets,
+ };
+
+ for (auto* fileSetType : fileSetTypes) {
+ if (fileSetType->WriteProperties(this, this->impl.get(), prop, value,
+ FileSetType::Action::Set)) {
+ return;
}
- } else if (prop == propIMPORTED_GLOBAL) {
+ }
+
+ if (prop == propIMPORTED_GLOBAL) {
if (!cmIsOn(value)) {
std::ostringstream e;
e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\""
@@ -1680,15 +1809,6 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
} else {
this->impl->LanguageStandardProperties.erase(prop);
}
- } else if (this->impl->HeadersFileSets.WriteProperties(
- this, this->impl.get(), prop, value, true)) {
- /* Handled in the `if` condition. */
- } else if (this->impl->CxxModulesFileSets.WriteProperties(
- this, this->impl.get(), prop, value, true)) {
- /* Handled in the `if` condition. */
- } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
- this, this->impl.get(), prop, value, true)) {
- /* Handled in the `if` condition. */
} else {
this->impl->Properties.SetProperty(prop, value);
}
@@ -1726,74 +1846,52 @@ void cmTarget::AppendProperty(const std::string& prop,
this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
- if (prop == "INCLUDE_DIRECTORIES") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->IncludeDirectoriesEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "COMPILE_OPTIONS") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->CompileOptionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "COMPILE_FEATURES") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->CompileFeaturesEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "COMPILE_DEFINITIONS") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->CompileDefinitionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "LINK_OPTIONS") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkOptionsEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "LINK_DIRECTORIES") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkDirectoriesEntries.emplace_back(value, 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());
+ if (prop == propPRECOMPILE_HEADERS &&
+ 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;
+ }
+
+ UsageRequirementProperty* usageRequirements[] = {
+ &this->impl->IncludeDirectories,
+ &this->impl->CompileOptions,
+ &this->impl->CompileFeatures,
+ &this->impl->CompileDefinitions,
+ &this->impl->PrecompileHeaders,
+ &this->impl->Sources,
+ &this->impl->LinkOptions,
+ &this->impl->LinkDirectories,
+ &this->impl->LinkLibraries,
+ &this->impl->InterfaceLinkLibraries,
+ &this->impl->InterfaceLinkLibrariesDirect,
+ &this->impl->InterfaceLinkLibrariesDirectExclude,
+ };
+
+ for (auto* usageRequirement : usageRequirements) {
+ if (usageRequirement->Write(this->impl.get(), bt, prop, cmValue(value),
+ UsageRequirementProperty::Action::Append)) {
return;
}
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->PrecompileHeadersEntries.emplace_back(value, lfbt);
- }
- } else if (prop == "LINK_LIBRARIES") {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt);
- }
- } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value,
- lfbt);
- }
- } else if (prop == "SOURCES") {
- cmListFileBacktrace lfbt = this->impl->GetBacktrace(bt);
- this->impl->SourceEntries.emplace_back(value, lfbt);
- } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) {
+ }
+
+ FileSetType* fileSetTypes[] = {
+ &this->impl->HeadersFileSets,
+ &this->impl->CxxModulesFileSets,
+ &this->impl->CxxModuleHeadersFileSets,
+ };
+
+ for (auto* fileSetType : fileSetTypes) {
+ if (fileSetType->WriteProperties(this, this->impl.get(), prop, value,
+ FileSetType::Action::Append)) {
+ return;
+ }
+ }
+
+ 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" ||
@@ -1801,16 +1899,6 @@ void cmTarget::AppendProperty(const std::string& prop,
prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") {
this->impl->Makefile->IssueMessage(
MessageType::FATAL_ERROR, prop + " property may not be appended.");
- } else if (this->impl->HeadersFileSets.WriteProperties(
- this, this->impl.get(), prop, value,
- false)) { // NOLINT(bugprone-branch-clone)
- /* Handled in the `if` condition. */
- } else if (this->impl->CxxModulesFileSets.WriteProperties(
- this, this->impl.get(), prop, value, false)) {
- /* Handled in the `if` condition. */
- } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
- this, this->impl.get(), prop, value, false)) {
- /* Handled in the `if` condition. */
} else {
this->impl->Properties.AppendProperty(prop, value, asString);
}
@@ -1826,9 +1914,12 @@ void cmTarget::SetProperty(const std::string& prop, cmValue value)
}
template <typename ValueType>
-void cmTargetInternals::AddDirectoryToFileSet(
- cmTarget* self, std::string const& fileSetName, ValueType value,
- cm::string_view fileSetType, cm::string_view description, bool clear)
+void cmTargetInternals::AddDirectoryToFileSet(cmTarget* self,
+ std::string const& fileSetName,
+ ValueType value,
+ cm::string_view fileSetType,
+ cm::string_view description,
+ FileSetType::Action action)
{
auto* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
@@ -1844,19 +1935,22 @@ void cmTargetInternals::AddDirectoryToFileSet(
"\"."));
return;
}
- if (clear) {
+ if (action == FileSetType::Action::Set) {
fileSet->ClearDirectoryEntries();
}
- if (!StringIsEmpty(value)) {
+ if (cmNonempty(value)) {
fileSet->AddDirectoryEntry(
BT<std::string>(value, this->Makefile->GetBacktrace()));
}
}
template <typename ValueType>
-void cmTargetInternals::AddPathToFileSet(
- cmTarget* self, std::string const& fileSetName, ValueType value,
- cm::string_view fileSetType, cm::string_view description, bool clear)
+void cmTargetInternals::AddPathToFileSet(cmTarget* self,
+ std::string const& fileSetName,
+ ValueType value,
+ cm::string_view fileSetType,
+ cm::string_view description,
+ FileSetType::Action action)
{
auto* fileSet = self->GetFileSet(fileSetName);
if (!fileSet) {
@@ -1872,10 +1966,10 @@ void cmTargetInternals::AddPathToFileSet(
"\"."));
return;
}
- if (clear) {
+ if (action == FileSetType::Action::Set) {
fileSet->ClearFileEntries();
}
- if (!StringIsEmpty(value)) {
+ if (cmNonempty(value)) {
fileSet->AddFileEntry(
BT<std::string>(value, this->Makefile->GetBacktrace()));
}
@@ -1949,8 +2043,7 @@ void cmTarget::AppendBuildInterfaceIncludes()
}
namespace {
-bool CheckLinkLibraryPattern(cm::string_view property,
- const std::vector<BT<std::string>>& value,
+bool CheckLinkLibraryPattern(UsageRequirementProperty const& usage,
cmake* context)
{
// Look for <LINK_LIBRARY:> and </LINK_LIBRARY:> internal tags
@@ -1959,7 +2052,7 @@ bool CheckLinkLibraryPattern(cm::string_view property,
bool isValid = true;
- for (const auto& item : value) {
+ for (const auto& item : usage.Entries) {
if (!linkPattern.find(item.Value)) {
continue;
}
@@ -1970,8 +2063,8 @@ bool CheckLinkLibraryPattern(cm::string_view property,
context->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat(
- "Property ", property, " contains the invalid item \"",
- linkPattern.match(2), "\". The ", property,
+ "Property ", usage.Name, " contains the invalid item \"",
+ linkPattern.match(2), "\". The ", usage.Name,
" property may contain the generator-expression \"$<LINK_",
linkPattern.match(3),
":...>\" which may be used to specify how the libraries are linked."),
@@ -1990,14 +2083,11 @@ void cmTarget::FinalizeTargetConfiguration(
return;
}
- if (!CheckLinkLibraryPattern("LINK_LIBRARIES"_s,
- this->impl->LinkImplementationPropertyEntries,
+ if (!CheckLinkLibraryPattern(this->impl->LinkLibraries,
this->GetMakefile()->GetCMakeInstance()) ||
- !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES"_s,
- this->impl->LinkInterfacePropertyEntries,
+ !CheckLinkLibraryPattern(this->impl->InterfaceLinkLibraries,
this->GetMakefile()->GetCMakeInstance()) ||
- !CheckLinkLibraryPattern("INTERFACE_LINK_LIBRARIES_DIRECT"_s,
- this->impl->LinkInterfaceDirectPropertyEntries,
+ !CheckLinkLibraryPattern(this->impl->InterfaceLinkLibrariesDirect,
this->GetMakefile()->GetCMakeInstance())) {
return;
}
@@ -2041,44 +2131,46 @@ void cmTarget::FinalizeTargetConfiguration(
void cmTarget::InsertInclude(BT<std::string> const& entry, bool before)
{
- auto position = before ? this->impl->IncludeDirectoriesEntries.begin()
- : this->impl->IncludeDirectoriesEntries.end();
-
- this->impl->IncludeDirectoriesEntries.insert(position, entry);
+ this->impl->IncludeDirectories.WriteDirect(
+ entry,
+ before ? UsageRequirementProperty::Action::Prepend
+ : UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertCompileOption(BT<std::string> const& entry, bool before)
{
- auto position = before ? this->impl->CompileOptionsEntries.begin()
- : this->impl->CompileOptionsEntries.end();
-
- this->impl->CompileOptionsEntries.insert(position, entry);
+ this->impl->CompileOptions.WriteDirect(
+ entry,
+ before ? UsageRequirementProperty::Action::Prepend
+ : UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertCompileDefinition(BT<std::string> const& entry)
{
- this->impl->CompileDefinitionsEntries.push_back(entry);
+ this->impl->CompileDefinitions.WriteDirect(
+ entry, UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertLinkOption(BT<std::string> const& entry, bool before)
{
- auto position = before ? this->impl->LinkOptionsEntries.begin()
- : this->impl->LinkOptionsEntries.end();
-
- this->impl->LinkOptionsEntries.insert(position, entry);
+ this->impl->LinkOptions.WriteDirect(
+ entry,
+ before ? UsageRequirementProperty::Action::Prepend
+ : UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertLinkDirectory(BT<std::string> const& entry, bool before)
{
- auto position = before ? this->impl->LinkDirectoriesEntries.begin()
- : this->impl->LinkDirectoriesEntries.end();
-
- this->impl->LinkDirectoriesEntries.insert(position, entry);
+ this->impl->LinkDirectories.WriteDirect(
+ entry,
+ before ? UsageRequirementProperty::Action::Prepend
+ : UsageRequirementProperty::Action::Append);
}
void cmTarget::InsertPrecompileHeader(BT<std::string> const& entry)
{
- this->impl->PrecompileHeadersEntries.push_back(entry);
+ this->impl->PrecompileHeaders.WriteDirect(
+ entry, UsageRequirementProperty::Action::Append);
}
namespace {
@@ -2223,102 +2315,33 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
}
return cmValue(propertyIter->second.Value);
}
- if (prop == propLINK_LIBRARIES) {
- if (this->impl->LinkImplementationPropertyEntries.empty()) {
- return nullptr;
- }
- static std::string output;
- output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
- return cmValue(output);
- }
- if (prop == propINTERFACE_LINK_LIBRARIES) {
- if (this->impl->LinkInterfacePropertyEntries.empty()) {
- return nullptr;
- }
+ UsageRequirementProperty const* usageRequirements[] = {
+ &this->impl->IncludeDirectories,
+ &this->impl->CompileOptions,
+ &this->impl->CompileFeatures,
+ &this->impl->CompileDefinitions,
+ &this->impl->PrecompileHeaders,
+ &this->impl->Sources,
+ &this->impl->LinkOptions,
+ &this->impl->LinkDirectories,
+ &this->impl->LinkLibraries,
+ &this->impl->InterfaceLinkLibraries,
+ &this->impl->InterfaceLinkLibrariesDirect,
+ &this->impl->InterfaceLinkLibrariesDirectExclude,
+ };
- static std::string output;
- output = cmJoin(this->impl->LinkInterfacePropertyEntries, ";");
- return cmValue(output);
- }
- if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) {
- if (this->impl->LinkInterfaceDirectPropertyEntries.empty()) {
- return nullptr;
+ for (auto const* usageRequirement : usageRequirements) {
+ auto value = usageRequirement->Read(prop);
+ if (value.first) {
+ return value.second;
}
-
- static std::string output;
- output = cmJoin(this->impl->LinkInterfaceDirectPropertyEntries, ";");
- return cmValue(output);
}
- if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) {
- if (this->impl->LinkInterfaceDirectExcludePropertyEntries.empty()) {
- return nullptr;
- }
- static std::string output;
- output =
- cmJoin(this->impl->LinkInterfaceDirectExcludePropertyEntries, ";");
- return cmValue(output);
- }
// the type property returns what type the target is
if (prop == propTYPE) {
return cmValue(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 cmValue(output);
- }
- if (prop == propCOMPILE_FEATURES) {
- if (this->impl->CompileFeaturesEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->CompileFeaturesEntries, ";");
- return cmValue(output);
- }
- if (prop == propCOMPILE_OPTIONS) {
- if (this->impl->CompileOptionsEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->CompileOptionsEntries, ";");
- return cmValue(output);
- }
- if (prop == propCOMPILE_DEFINITIONS) {
- if (this->impl->CompileDefinitionsEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
- return cmValue(output);
- }
- if (prop == propLINK_OPTIONS) {
- if (this->impl->LinkOptionsEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->LinkOptionsEntries, ";");
- return cmValue(output);
- }
- if (prop == propLINK_DIRECTORIES) {
- if (this->impl->LinkDirectoriesEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
-
- return cmValue(output);
- }
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
if (this->impl->Utilities.empty()) {
return nullptr;
@@ -2336,15 +2359,6 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
output = cmJoin(utilities, ";");
return cmValue(output);
}
- if (prop == propPRECOMPILE_HEADERS) {
- if (this->impl->PrecompileHeadersEntries.empty()) {
- return nullptr;
- }
-
- static std::string output;
- output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
- return cmValue(output);
- }
if (prop == propIMPORTED) {
return this->IsImported() ? cmValue(propTRUE) : cmValue(propFALSE);
}
@@ -2369,21 +2383,17 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
// Check fileset properties.
{
- auto headers =
- this->impl->HeadersFileSets.ReadProperties(this, this->impl.get(), prop);
- if (headers.first) {
- return headers.second;
- }
- auto cxx_modules = this->impl->CxxModulesFileSets.ReadProperties(
- this, this->impl.get(), prop);
- if (cxx_modules.first) {
- return cxx_modules.second;
- }
- auto cxx_module_headers =
- this->impl->CxxModuleHeadersFileSets.ReadProperties(
- this, this->impl.get(), prop);
- if (cxx_module_headers.first) {
- return cxx_module_headers.second;
+ FileSetType* fileSetTypes[] = {
+ &this->impl->HeadersFileSets,
+ &this->impl->CxxModulesFileSets,
+ &this->impl->CxxModuleHeadersFileSets,
+ };
+
+ for (auto* fileSetType : fileSetTypes) {
+ auto value = fileSetType->ReadProperties(this, this->impl.get(), prop);
+ if (value.first) {
+ return value.second;
+ }
}
}
@@ -2657,7 +2667,8 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
const std::string& name, const std::string& type, cmFileSetVisibility vis)
{
auto result = this->impl->FileSets.emplace(
- std::make_pair(name, cmFileSet(name, type, vis)));
+ name,
+ cmFileSet(*this->GetMakefile()->GetCMakeInstance(), name, type, vis));
if (result.second) {
auto bt = this->impl->Makefile->GetBacktrace();
if (type == this->impl->HeadersFileSets.TypeName) {
diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx
index cb83873..7a2dd09 100644
--- a/Source/cmTargetIncludeDirectoriesCommand.cxx
+++ b/Source/cmTargetIncludeDirectoriesCommand.cxx
@@ -100,8 +100,7 @@ bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args,
{
return TargetIncludeDirectoriesImpl(status).HandleArguments(
args, "INCLUDE_DIRECTORIES",
- static_cast<TargetIncludeDirectoriesImpl::ArgumentFlags>(
- TargetIncludeDirectoriesImpl::PROCESS_BEFORE |
+ TargetIncludeDirectoriesImpl::PROCESS_BEFORE |
TargetIncludeDirectoriesImpl::PROCESS_AFTER |
- TargetIncludeDirectoriesImpl::PROCESS_SYSTEM));
+ TargetIncludeDirectoriesImpl::PROCESS_SYSTEM);
}
diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx
index 391b954..8d2ff71 100644
--- a/Source/cmTargetPropCommandBase.cxx
+++ b/Source/cmTargetPropCommandBase.cxx
@@ -23,7 +23,7 @@ void cmTargetPropCommandBase::SetError(std::string const& e)
bool cmTargetPropCommandBase::HandleArguments(
std::vector<std::string> const& args, const std::string& prop,
- ArgumentFlags flags)
+ unsigned int flags)
{
if (args.size() < 2) {
this->SetError("called with incorrect number of arguments");
diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h
index 6bf7c3c..ac50b4d 100644
--- a/Source/cmTargetPropCommandBase.h
+++ b/Source/cmTargetPropCommandBase.h
@@ -24,13 +24,12 @@ public:
NO_FLAGS = 0x0,
PROCESS_BEFORE = 0x1,
PROCESS_AFTER = 0x2,
- PROCESS_SYSTEM = 0x3,
- PROCESS_REUSE_FROM = 0x4
+ PROCESS_SYSTEM = 0x4,
+ PROCESS_REUSE_FROM = 0x8
};
bool HandleArguments(std::vector<std::string> const& args,
- const std::string& prop,
- ArgumentFlags flags = NO_FLAGS);
+ const std::string& prop, unsigned int flags = NO_FLAGS);
protected:
std::string Property;
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index dbb0876..5e325dd 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -127,7 +127,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
this->TestGenerated = true;
// Set up generator expression evaluation context.
- cmGeneratorExpression ge(this->Test->GetBacktrace());
+ cmGeneratorExpression ge(*this->Test->GetMakefile()->GetCMakeInstance(),
+ this->Test->GetBacktrace());
// Determine if policy CMP0110 is set to NEW.
const bool quote_test_name =
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 677fdb6..7e47b4e 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -128,8 +128,8 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
: static_cast<char>(0);
if (c1 == '%' && c2 != 0) {
- result +=
- this->AddTimestampComponent(c2, timeStruct, timeT, microseconds);
+ result += this->AddTimestampComponent(c2, timeStruct, timeT, utcFlag,
+ microseconds);
++i;
} else {
result += c1;
@@ -179,7 +179,7 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const
}
std::string cmTimestamp::AddTimestampComponent(
- char flag, struct tm& timeStruct, const time_t timeT,
+ char flag, struct tm& timeStruct, const time_t timeT, const bool utcFlag,
const uint32_t microseconds) const
{
std::string formatString = cmStrCat('%', flag);
@@ -203,6 +203,63 @@ std::string cmTimestamp::AddTimestampComponent(
case 'Y':
case '%':
break;
+ case 'Z':
+#if defined(__GLIBC__)
+ // 'struct tm' has the time zone, so strftime can honor UTC.
+ static_cast<void>(utcFlag);
+#else
+ // 'struct tm' may not have the time zone, so strftime may
+ // use local time. Hard-code the UTC result.
+ if (utcFlag) {
+ return std::string("GMT");
+ }
+#endif
+ break;
+ case 'z': {
+#if defined(__GLIBC__)
+ // 'struct tm' has the time zone, so strftime can honor UTC.
+ static_cast<void>(utcFlag);
+#else
+ // 'struct tm' may not have the time zone, so strftime may
+ // use local time. Hard-code the UTC result.
+ if (utcFlag) {
+ return std::string("+0000");
+ }
+#endif
+#ifndef _AIX
+ break;
+#else
+ std::string xpg_sus_old;
+ bool const xpg_sus_was_set =
+ cmSystemTools::GetEnv("XPG_SUS_ENV", xpg_sus_old);
+ if (xpg_sus_was_set && xpg_sus_old == "ON") {
+ break;
+ }
+ xpg_sus_old = "XPG_SUS_ENV=" + xpg_sus_old;
+
+ // On AIX systems, %z requires XPG_SUS_ENV=ON to work as desired.
+ cmSystemTools::PutEnv("XPG_SUS_ENV=ON");
+ tzset();
+
+ char buffer[16];
+ size_t size = strftime(buffer, sizeof(buffer), "%z", &timeStruct);
+
+# ifndef CMAKE_BOOTSTRAP
+ if (xpg_sus_was_set) {
+ cmSystemTools::PutEnv(xpg_sus_old);
+ } else {
+ cmSystemTools::UnsetEnv("XPG_SUS_ENV");
+ }
+# else
+ // No UnsetEnv during bootstrap. This is good enough for CMake itself.
+ cmSystemTools::PutEnv(xpg_sus_old);
+ static_cast<void>(xpg_sus_was_set);
+# endif
+ tzset();
+
+ return std::string(buffer, size);
+#endif
+ }
case 's': // Seconds since UNIX epoch (midnight 1-jan-1970)
{
// Build a time_t for UNIX epoch and subtract from the input "timeT":
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
index ada5006..05c6342 100644
--- a/Source/cmTimestamp.h
+++ b/Source/cmTimestamp.h
@@ -32,6 +32,6 @@ private:
time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const;
std::string AddTimestampComponent(char flag, struct tm& timeStruct,
- time_t timeT,
- uint32_t microseconds = 0) const;
+ time_t timeT, bool utcFlag,
+ uint32_t microseconds) const;
};
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index a2c4ce1..d2cc75b 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -2,6 +2,9 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTryCompileCommand.h"
+#include <cm/optional>
+
+#include "cmConfigureLog.h"
#include "cmCoreTryCompile.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
@@ -13,6 +16,23 @@
#include "cmValue.h"
#include "cmake.h"
+namespace {
+#ifndef CMAKE_BOOTSTRAP
+void WriteTryCompileEvent(cmConfigureLog& log, cmMakefile const& mf,
+ cmTryCompileResult const& compileResult)
+{
+ // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
+ static const std::vector<unsigned long> LogVersionsWithTryCompileV1{ 1 };
+
+ if (log.IsAnyLogVersionEnabled(LogVersionsWithTryCompileV1)) {
+ log.BeginEvent("try_compile-v1", mf);
+ cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult);
+ log.EndEvent();
+ }
+}
+#endif
+}
+
bool cmTryCompileCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -59,7 +79,16 @@ bool cmTryCompileCommand(std::vector<std::string> const& args,
if (!arguments) {
return true;
}
- tc.TryCompileCode(arguments, targetType);
+
+ cm::optional<cmTryCompileResult> compileResult =
+ tc.TryCompileCode(arguments, targetType);
+#ifndef CMAKE_BOOTSTRAP
+ if (compileResult && !arguments.NoLog) {
+ if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
+ WriteTryCompileEvent(*log, mf, *compileResult);
+ }
+ }
+#endif
// if They specified clean then we clean up what we can
if (tc.SrcFileSignature) {
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index 8d62cb1..b648d9b 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -3,12 +3,15 @@
#include "cmTryRunCommand.h"
#include <cstdio>
+#include <stdexcept>
#include <cm/optional>
+#include <cmext/string_view>
#include "cmsys/FStream.hxx"
#include "cmArgumentParserTypes.h"
+#include "cmConfigureLog.h"
#include "cmCoreTryCompile.h"
#include "cmDuration.h"
#include "cmExecutionStatus.h"
@@ -23,6 +26,48 @@
#include "cmake.h"
namespace {
+struct cmTryRunResult
+{
+ bool VariableCached = true;
+ std::string Variable;
+ cm::optional<std::string> Stdout;
+ cm::optional<std::string> Stderr;
+ cm::optional<std::string> ExitCode;
+};
+
+#ifndef CMAKE_BOOTSTRAP
+void WriteTryRunEvent(cmConfigureLog& log, cmMakefile const& mf,
+ cmTryCompileResult const& compileResult,
+ cmTryRunResult const& runResult)
+{
+ // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
+ static const std::vector<unsigned long> LogVersionsWithTryRunV1{ 1 };
+
+ if (log.IsAnyLogVersionEnabled(LogVersionsWithTryRunV1)) {
+ log.BeginEvent("try_run-v1", mf);
+ cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult);
+
+ log.BeginObject("runResult"_s);
+ log.WriteValue("variable"_s, runResult.Variable);
+ log.WriteValue("cached"_s, runResult.VariableCached);
+ if (runResult.Stdout) {
+ log.WriteLiteralTextBlock("stdout"_s, *runResult.Stdout);
+ }
+ if (runResult.Stderr) {
+ log.WriteLiteralTextBlock("stderr"_s, *runResult.Stderr);
+ }
+ if (runResult.ExitCode) {
+ try {
+ log.WriteValue("exitCode"_s, std::stoi(*runResult.ExitCode));
+ } catch (std::invalid_argument const&) {
+ log.WriteValue("exitCode"_s, *runResult.ExitCode);
+ }
+ }
+ log.EndObject();
+ log.EndEvent();
+ }
+}
+#endif
class TryRunCommandImpl : public cmCoreTryCompile
{
@@ -44,7 +89,8 @@ public:
std::string const& compileResultVariable,
std::string* runOutputContents,
std::string* runOutputStdOutContents,
- std::string* runOutputStdErrContents);
+ std::string* runOutputStdErrContents,
+ bool stdOutErrRequired);
bool NoCache;
std::string RunResultVariable;
@@ -96,23 +142,35 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
}
bool captureRunOutput = false;
- bool captureRunOutputStdOutErr = false;
if (arguments.OutputVariable) {
captureRunOutput = true;
} else if (arguments.CompileOutputVariable) {
arguments.OutputVariable = arguments.CompileOutputVariable;
}
- if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) {
- captureRunOutputStdOutErr = true;
- } else if (arguments.RunOutputVariable) {
- captureRunOutput = true;
+
+ // Capture the split output for the configure log unless the caller
+ // requests combined output to be captured by a variable.
+ bool captureRunOutputStdOutErr = true;
+ if (!arguments.RunOutputStdOutVariable &&
+ !arguments.RunOutputStdErrVariable) {
+ if (arguments.RunOutputVariable) {
+ captureRunOutput = true;
+ captureRunOutputStdOutErr = false;
+ } else if (arguments.OutputVariable) {
+ captureRunOutputStdOutErr = false;
+ }
}
// do the try compile
- bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
+ cm::optional<cmTryCompileResult> compileResult =
+ this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE);
+
+ cmTryRunResult runResult;
+ runResult.Variable = this->RunResultVariable;
+ runResult.VariableCached = !arguments.NoCache;
// now try running the command if it compiled
- if (compiled) {
+ if (compileResult && compileResult->ExitCode == 0) {
if (this->OutputFile.empty()) {
cmSystemTools::Error(this->FindErrorMessage);
} else {
@@ -127,26 +185,35 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
std::string runOutputStdErrContents;
if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") &&
!this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) {
+ // We only require the stdout/stderr cache entries if the project
+ // actually asked for the values, not just for logging.
+ bool const stdOutErrRequired = (arguments.RunOutputStdOutVariable ||
+ arguments.RunOutputStdErrVariable);
this->DoNotRunExecutable(
runArgs, arguments.SourceDirectoryOrFile,
*arguments.CompileResultVariable,
captureRunOutput ? &runOutputContents : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
- ? &runOutputStdOutContents
- : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
- ? &runOutputStdErrContents
- : nullptr);
+ captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr,
+ captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr,
+ stdOutErrRequired);
} else {
this->RunExecutable(
runArgs, arguments.RunWorkingDirectory,
captureRunOutput ? &runOutputContents : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable
- ? &runOutputStdOutContents
- : nullptr,
- captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable
- ? &runOutputStdErrContents
- : nullptr);
+ captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr,
+ captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr);
+ }
+
+ if (captureRunOutputStdOutErr) {
+ runResult.Stdout = runOutputStdOutContents;
+ runResult.Stderr = runOutputStdErrContents;
+ } else {
+ runResult.Stdout = runOutputContents;
+ }
+
+ if (cmValue ec =
+ this->Makefile->GetDefinition(this->RunResultVariable)) {
+ runResult.ExitCode = *ec;
}
// now put the output into the variables
@@ -177,6 +244,15 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv)
}
}
+#ifndef CMAKE_BOOTSTRAP
+ if (compileResult && !arguments.NoLog) {
+ cmMakefile const& mf = *(this->Makefile);
+ if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) {
+ WriteTryRunEvent(*log, mf, *compileResult, runResult);
+ }
+ }
+#endif
+
// if we created a directory etc, then cleanup after ourselves
if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) {
this->CleanupFiles(this->BinaryDirectory);
@@ -240,7 +316,7 @@ void TryRunCommandImpl::RunExecutable(const std::string& runArgs,
void TryRunCommandImpl::DoNotRunExecutable(
const std::string& runArgs, cm::optional<std::string> const& srcFile,
std::string const& compileResultVariable, std::string* out,
- std::string* stdOut, std::string* stdErr)
+ std::string* stdOut, std::string* stdErr, bool stdOutErrRequired)
{
// 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
@@ -286,7 +362,7 @@ void TryRunCommandImpl::DoNotRunExecutable(
}
// is the output from the executable used ?
- if (stdOut || stdErr) {
+ if (stdOutErrRequired) {
if (!this->Makefile->GetDefinition(internalRunOutputStdOutName)) {
// if the variables doesn't exist, create it with a helpful error text
// and mark it as advanced
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index 6040fd8..3faf2f6 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -241,6 +241,7 @@ bool cmUVProcessChain::InternalData::AddCommand(
options.file = config.Arguments[0].c_str();
std::vector<const char*> arguments;
+ arguments.reserve(config.Arguments.size());
for (auto const& arg : config.Arguments) {
arguments.push_back(arg.c_str());
}
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
index 8764f21..6702b7b 100644
--- a/Source/cmVSSetupHelper.cxx
+++ b/Source/cmVSSetupHelper.cxx
@@ -87,12 +87,11 @@ std::string VSInstanceInfo::GetInstallLocation() const
cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version)
: Version(version)
- , setupConfig(NULL)
- , setupConfig2(NULL)
- , setupHelper(NULL)
- , initializationFailure(false)
+ , setupConfig(nullptr)
+ , setupConfig2(nullptr)
+ , setupHelper(nullptr)
{
- comInitialized = CoInitializeEx(NULL, 0);
+ comInitialized = CoInitializeEx(nullptr, 0);
if (SUCCEEDED(comInitialized)) {
Initialize();
} else {
@@ -102,11 +101,12 @@ cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version)
cmVSSetupAPIHelper::~cmVSSetupAPIHelper()
{
- setupHelper = NULL;
- setupConfig2 = NULL;
- setupConfig = NULL;
- if (SUCCEEDED(comInitialized))
+ setupHelper = nullptr;
+ setupConfig2 = nullptr;
+ setupConfig = nullptr;
+ if (SUCCEEDED(comInitialized)) {
CoUninitialize();
+ }
}
bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation,
@@ -159,12 +159,12 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent(
// the
// component name ex: Microsoft.VisualStudio.Component.Windows10SDK.10240
if (id.find(Win10SDKComponent) != std::wstring::npos &&
- type.compare(ComponentType) == 0) {
+ type == ComponentType) {
bWin10SDK = true;
ret = true;
}
- if (id.compare(Win81SDKComponent) == 0 && type.compare(ComponentType) == 0) {
+ if (id == Win81SDKComponent && type == ComponentType) {
bWin81SDK = true;
ret = true;
}
@@ -177,8 +177,9 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent(
bool cmVSSetupAPIHelper::GetVSInstanceInfo(
SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo)
{
- if (pInstance == NULL)
+ if (pInstance == nullptr) {
return false;
+ }
InstanceState state;
if (FAILED(pInstance->GetState(&state))) {
@@ -188,21 +189,19 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
SmartBSTR bstrVersion;
if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) {
return false;
- } else {
- vsInstanceInfo.Version =
- cmsys::Encoding::ToNarrow(std::wstring(bstrVersion));
}
+ vsInstanceInfo.Version =
+ cmsys::Encoding::ToNarrow(std::wstring(bstrVersion));
// 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 =
- cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath));
- cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation);
}
+ vsInstanceInfo.VSInstallLocation =
+ cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath));
+ cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation);
}
// Check if a compiler is installed with this instance.
@@ -220,7 +219,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
LPSAFEARRAY lpsaPackages;
if (FAILED(pInstance->GetPackages(&lpsaPackages)) ||
- lpsaPackages == NULL) {
+ lpsaPackages == nullptr) {
return false;
}
@@ -229,11 +228,12 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(
IUnknown** ppData = (IUnknown**)lpsaPackages->pvData;
for (int i = lower; i < upper; i++) {
- SmartCOMPtr<ISetupPackageReference> package = NULL;
+ SmartCOMPtr<ISetupPackageReference> package = nullptr;
if (FAILED(ppData[i]->QueryInterface(IID_ISetupPackageReference,
(void**)&package)) ||
- package == NULL)
+ package == nullptr) {
continue;
+ }
bool win10SDKInstalled = false;
bool win81SDkInstalled = false;
@@ -289,7 +289,8 @@ bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion)
bool cmVSSetupAPIHelper::IsEWDKEnabled()
{
- std::string envEnterpriseWDK, envDisableRegistryUse;
+ std::string envEnterpriseWDK;
+ std::string envDisableRegistryUse;
cmSystemTools::GetEnv("EnterpriseWDK", envEnterpriseWDK);
cmSystemTools::GetEnv("DisableRegistryUse", envDisableRegistryUse);
if (!cmSystemTools::Strucmp(envEnterpriseWDK.c_str(), "True") &&
@@ -370,11 +371,12 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere(
bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM(
std::vector<VSInstanceInfo>& VSInstances)
{
- if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL ||
- setupHelper == NULL)
+ if (initializationFailure || setupConfig == nullptr ||
+ setupConfig2 == nullptr || setupHelper == nullptr) {
return false;
+ }
- SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
+ SmartCOMPtr<IEnumSetupInstances> enumInstances = nullptr;
if (FAILED(
setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
!enumInstances) {
@@ -382,20 +384,21 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM(
}
SmartCOMPtr<ISetupInstance> instance;
- while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
- SmartCOMPtr<ISetupInstance2> instance2 = NULL;
+ while (SUCCEEDED(enumInstances->Next(1, &instance, nullptr)) && instance) {
+ SmartCOMPtr<ISetupInstance2> instance2 = nullptr;
if (FAILED(
instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) ||
!instance2) {
- instance = NULL;
+ instance = nullptr;
continue;
}
VSInstanceInfo instanceInfo;
bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo);
- instance = instance2 = NULL;
- if (isInstalled)
+ instance = instance2 = nullptr;
+ if (isInstalled) {
VSInstances.push_back(instanceInfo);
+ }
}
return true;
}
@@ -403,18 +406,21 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM(
bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
{
bool isVSInstanceExists = false;
- if (chosenInstanceInfo.VSInstallLocation.compare("") != 0) {
+ if (!chosenInstanceInfo.VSInstallLocation.empty()) {
return true;
}
if (this->IsEWDKEnabled()) {
- std::string envWindowsSdkDir81, envVSVersion, envVsInstallDir;
+ std::string envWindowsSdkDir81;
+ std::string envVSVersion;
+ std::string envVsInstallDir;
cmSystemTools::GetEnv("WindowsSdkDir_81", envWindowsSdkDir81);
cmSystemTools::GetEnv("VisualStudioVersion", envVSVersion);
cmSystemTools::GetEnv("VSINSTALLDIR", envVsInstallDir);
- if (envVSVersion.empty() || envVsInstallDir.empty())
+ if (envVSVersion.empty() || envVsInstallDir.empty()) {
return false;
+ }
chosenInstanceInfo.VSInstallLocation = envVsInstallDir;
chosenInstanceInfo.Version = envVSVersion;
@@ -499,7 +505,7 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
return this->LoadSpecifiedVSInstanceFromDisk();
}
- if (vecVSInstances.size() > 0) {
+ if (!vecVSInstances.empty()) {
isVSInstanceExists = true;
int index = ChooseVSInstance(vecVSInstances);
chosenInstanceInfo = vecVSInstances[index];
@@ -511,11 +517,13 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
int cmVSSetupAPIHelper::ChooseVSInstance(
const std::vector<VSInstanceInfo>& vecVSInstances)
{
- if (vecVSInstances.size() == 0)
+ if (vecVSInstances.empty()) {
return -1;
+ }
- if (vecVSInstances.size() == 1)
+ if (vecVSInstances.size() == 1) {
return 0;
+ }
unsigned int chosenIndex = 0;
for (unsigned int i = 1; i < vecVSInstances.size(); i++) {
@@ -589,32 +597,33 @@ bool cmVSSetupAPIHelper::LoadSpecifiedVSInstanceFromDisk()
bool cmVSSetupAPIHelper::Initialize()
{
- if (initializationFailure)
+ if (initializationFailure) {
return false;
+ }
if (FAILED(comInitialized)) {
initializationFailure = true;
return false;
}
- if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, NULL,
+ if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, nullptr,
IID_ISetupConfiguration,
CLSCTX_INPROC_SERVER)) ||
- setupConfig == NULL) {
+ setupConfig == nullptr) {
initializationFailure = true;
return false;
}
if (FAILED(setupConfig.QueryInterface(IID_ISetupConfiguration2,
(void**)&setupConfig2)) ||
- setupConfig2 == NULL) {
+ setupConfig2 == nullptr) {
initializationFailure = true;
return false;
}
if (FAILED(
setupConfig.QueryInterface(IID_ISetupHelper, (void**)&setupHelper)) ||
- setupHelper == NULL) {
+ setupHelper == nullptr) {
initializationFailure = true;
return false;
}
diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h
index a16f00b..b8be9b9 100644
--- a/Source/cmVSSetupHelper.h
+++ b/Source/cmVSSetupHelper.h
@@ -17,18 +17,20 @@ template <class T>
class SmartCOMPtr
{
public:
- SmartCOMPtr() { ptr = NULL; }
+ SmartCOMPtr() = default;
SmartCOMPtr(T* p)
{
ptr = p;
- if (ptr != NULL)
+ if (ptr != nullptr) {
ptr->AddRef();
+ }
}
SmartCOMPtr(const SmartCOMPtr<T>& sptr)
{
ptr = sptr.ptr;
- if (ptr != NULL)
+ if (ptr != nullptr) {
ptr->AddRef();
+ }
}
T** operator&() { return &ptr; }
T* operator->() { return ptr; }
@@ -36,8 +38,9 @@ public:
{
if (*this != p) {
ptr = p;
- if (ptr != NULL)
+ if (ptr != nullptr) {
ptr->AddRef();
+ }
}
return *this;
}
@@ -45,11 +48,10 @@ public:
template <class I>
HRESULT QueryInterface(REFCLSID rclsid, I** pp)
{
- if (pp != NULL) {
+ if (pp != nullptr) {
return ptr->QueryInterface(rclsid, (void**)pp);
- } else {
- return E_FAIL;
}
+ return E_FAIL;
}
HRESULT CoCreateInstance(REFCLSID clsid, IUnknown* pUnknown,
REFIID interfaceId, DWORD dwClsContext = CLSCTX_ALL)
@@ -60,18 +62,19 @@ public:
}
~SmartCOMPtr()
{
- if (ptr != NULL)
+ if (ptr != nullptr) {
ptr->Release();
+ }
}
private:
- T* ptr;
+ T* ptr = nullptr;
};
class SmartBSTR
{
public:
- SmartBSTR() { str = NULL; }
+ SmartBSTR() = default;
SmartBSTR(const SmartBSTR& src) = delete;
SmartBSTR& operator=(const SmartBSTR& src) = delete;
operator BSTR() const { return str; }
@@ -79,7 +82,7 @@ public:
~SmartBSTR() throw() { ::SysFreeString(str); }
private:
- BSTR str;
+ BSTR str = nullptr;
};
struct VSInstanceInfo
@@ -129,7 +132,7 @@ private:
SmartCOMPtr<ISetupConfiguration2> setupConfig2;
SmartCOMPtr<ISetupHelper> setupHelper;
// used to indicate failure in Initialize(), so we don't have to call again
- bool initializationFailure;
+ bool initializationFailure = false;
// indicated if COM initialization is successful
HRESULT comInitialized;
// current best instance of VS selected
diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in
index 06251f3..5d52950 100644
--- a/Source/cmVersionConfig.h.in
+++ b/Source/cmVersionConfig.h.in
@@ -1,5 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
#define CMake_VERSION_MAJOR @CMake_VERSION_MAJOR@
#define CMake_VERSION_MINOR @CMake_VERSION_MINOR@
#define CMake_VERSION_PATCH @CMake_VERSION_PATCH@
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 8882c45..c88679c 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -80,10 +80,10 @@ struct cmVisualStudio10TargetGenerator::Elem
bool HasContent = false;
std::string Tag;
- Elem(std::ostream& s, const std::string& tag)
+ Elem(std::ostream& s, std::string tag)
: S(s)
, Indent(0)
- , Tag(tag)
+ , Tag(std::move(tag))
{
this->StartElement();
}
@@ -200,7 +200,7 @@ struct cmVisualStudio10TargetGenerator::OptionsHelper
}
};
-static std::string cmVS10EscapeComment(std::string comment)
+static std::string cmVS10EscapeComment(std::string const& comment)
{
// MSBuild takes the CDATA of a <Message></Message> element and just
// does "echo $CDATA" with no escapes. We must encode the string.
@@ -275,8 +275,8 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
this->NsightTegra = gg->IsNsightTegra();
this->Android = gg->TargetsAndroid();
- for (int i = 0; i < 4; ++i) {
- this->NsightTegraVersion[i] = 0;
+ for (unsigned int& version : this->NsightTegraVersion) {
+ version = 0;
}
sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u",
&this->NsightTegraVersion[0], &this->NsightTegraVersion[1],
@@ -293,9 +293,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
this->ClassifyAllConfigSources();
}
-cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
-{
-}
+cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() = default;
std::string cmVisualStudio10TargetGenerator::CalcCondition(
const std::string& config) const
@@ -358,7 +356,8 @@ void cmVisualStudio10TargetGenerator::Generate()
this->GeneratorTarget->CheckCxxModuleStatus(config);
}
- if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
+ if (this->GeneratorTarget->HaveCxx20ModuleSources() &&
+ !this->GlobalGenerator->SupportsCxxModuleDyndep()) {
this->Makefile->IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("The \"", this->GeneratorTarget->GetName(),
@@ -406,6 +405,9 @@ void cmVisualStudio10TargetGenerator::Generate()
if (!this->ComputeCudaLinkOptions()) {
return;
}
+ if (!this->ComputeMarmasmOptions()) {
+ return;
+ }
if (!this->ComputeMasmOptions()) {
return;
}
@@ -423,7 +425,7 @@ void cmVisualStudio10TargetGenerator::Generate()
cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
this->Name, ProjectFileExtension);
cmGeneratedFileStream BuildFileStream(path);
- const std::string PathToProjectFile = path;
+ const std::string& PathToProjectFile = path;
BuildFileStream.SetCopyIfDifferent(true);
// Write the encoding header into the file
@@ -453,7 +455,7 @@ void cmVisualStudio10TargetGenerator::Generate()
void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
cmGeneratedFileStream& BuildFileStream)
{
- BuildFileStream << "<?xml version=\"1.0\" encoding=\""
+ BuildFileStream << R"(<?xml version="1.0" encoding=")"
<< this->GlobalGenerator->Encoding() << "\"?>";
{
Elem e0(BuildFileStream, "Project");
@@ -548,7 +550,7 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
e1.Element("Platform", this->Platform);
cmValue projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
- e1.Element("ProjectName", projLabel ? projLabel : this->Name);
+ e1.Element("ProjectName", projLabel ? *projLabel : this->Name);
{
cm::optional<std::string> targetFramework;
cm::optional<std::string> targetFrameworkVersion;
@@ -725,13 +727,18 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
: customDir +
this->GlobalGenerator
->GetPlatformToolsetCudaVSIntegrationSubdirString() +
- "extras\\visual_studio_integration\\MSBuildExtensions\\";
+ R"(extras\visual_studio_integration\MSBuildExtensions\)";
Elem(e1, "Import")
.Attribute("Project",
std::move(cudaPath) + "CUDA " +
this->GlobalGenerator->GetPlatformToolsetCuda() +
".props");
}
+ if (this->GlobalGenerator->IsMarmasmEnabled()) {
+ Elem(e1, "Import")
+ .Attribute("Project",
+ "$(VCTargetsPath)\\BuildCustomizations\\marmasm.props");
+ }
if (this->GlobalGenerator->IsMasmEnabled()) {
Elem(e1, "Import")
.Attribute("Project",
@@ -823,13 +830,18 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
: customDir +
this->GlobalGenerator
->GetPlatformToolsetCudaVSIntegrationSubdirString() +
- "extras\\visual_studio_integration\\MSBuildExtensions\\";
+ R"(extras\visual_studio_integration\MSBuildExtensions\)";
Elem(e1, "Import")
.Attribute("Project",
std::move(cudaPath) + "CUDA " +
this->GlobalGenerator->GetPlatformToolsetCuda() +
".targets");
}
+ if (this->GlobalGenerator->IsMarmasmEnabled()) {
+ Elem(e1, "Import")
+ .Attribute("Project",
+ "$(VCTargetsPath)\\BuildCustomizations\\marmasm.targets");
+ }
if (this->GlobalGenerator->IsMasmEnabled()) {
Elem(e1, "Import")
.Attribute("Project",
@@ -979,6 +991,8 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile(
this->WriteDotNetDocumentationFile(e0);
this->WriteAllSources(e0);
+ this->WriteEmbeddedResourceGroup(e0);
+ this->WriteXamlFilesGroup(e0);
this->WriteDotNetReferences(e0);
this->WritePackageReferences(e0);
this->WriteProjectReferences(e0);
@@ -1020,8 +1034,9 @@ void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
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))
+ 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" ||
@@ -1029,8 +1044,9 @@ void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1)
continue;
}
cmValue value = this->GeneratorTarget->GetProperty(keyIt);
- if (!value)
+ if (!value) {
continue;
+ }
e1.Element(globalKey, *value);
}
}
@@ -1043,14 +1059,11 @@ bool cmVisualStudio10TargetGenerator::HasCustomCommands() const
return true;
}
- for (cmGeneratorTarget::AllConfigSource const& si :
- this->GeneratorTarget->GetAllConfigSources()) {
- if (si.Source->GetCustomCommand()) {
- return true;
- }
- }
-
- return false;
+ auto const& config_sources = this->GeneratorTarget->GetAllConfigSources();
+ return std::any_of(config_sources.begin(), config_sources.end(),
+ [](cmGeneratorTarget::AllConfigSource const& si) {
+ return si.Source->GetCustomCommand();
+ });
}
void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
@@ -1220,7 +1233,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
e2.Attribute("Include", obj);
if (this->ProjectType != VsProjectType::csproj) {
- std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h";
+ std::string hFileName = obj.substr(0, obj.find_last_of('.')) + ".h";
e2.Element("DependentUpon", hFileName);
for (std::string const& c : this->Configurations) {
@@ -1793,8 +1806,13 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule(
this->WriteCustomRuleCSharp(e0, c, name, script, additional_inputs.str(),
outputs.str(), comment, ccg);
} else {
- this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(),
- outputs.str(), comment, ccg, symbolic);
+ this->WriteCustomRuleCpp(
+ *spe2, c, script, additional_inputs.str(), outputs.str(), comment, ccg,
+ symbolic,
+ (command.GetUsesTerminal() ||
+ (command.HasMainDependency() && source->GetIsGenerated()))
+ ? BuildInParallel::No
+ : BuildInParallel::Yes);
}
}
}
@@ -1803,9 +1821,13 @@ 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, cmCustomCommandGenerator const& ccg,
- bool symbolic)
+ bool symbolic, BuildInParallel buildInParallel)
{
const std::string cond = this->CalcCondition(config);
+ if (buildInParallel == BuildInParallel::Yes &&
+ this->GlobalGenerator->IsBuildInParallelSupported()) {
+ e2.WritePlatformConfigTag("BuildInParallel", cond, "true");
+ }
e2.WritePlatformConfigTag("Message", cond, comment);
e2.WritePlatformConfigTag("Command", cond, script);
e2.WritePlatformConfigTag("AdditionalInputs", cond, additional_inputs);
@@ -1912,7 +1934,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
fout.write(magic, 3);
- fout << "<?xml version=\"1.0\" encoding=\""
+ fout << R"(<?xml version="1.0" encoding=")"
<< this->GlobalGenerator->Encoding() << "\"?>";
{
Elem e0(fout, "Project");
@@ -2068,7 +2090,7 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource(
e2.Element("FileType", "CppForm");
} else if (this->IsXamlHeader(fileName)) {
e2.Element("DependentUpon",
- fileName.substr(0, fileName.find_last_of(".")));
+ fileName.substr(0, fileName.find_last_of('.')));
}
this->FinishWritingSource(e2, toolSettings);
}
@@ -2077,7 +2099,7 @@ void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
const std::string& settingsPropertyValue, ConfigToSettings& toolSettings)
{
if (!settingsPropertyValue.empty()) {
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
std::unique_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(settingsPropertyValue);
@@ -2104,7 +2126,7 @@ void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs(
const ConfigToSettings& toolSettings, const std::string& propName)
{
- std::string firstPropValue = "";
+ std::string firstPropValue;
for (const auto& configToSettings : toolSettings) {
const std::unordered_map<std::string, std::string>& settings =
configToSettings.second;
@@ -2177,7 +2199,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(
}
// Figure out if there's any additional flags to use
if (cmValue saf = sf->GetProperty("VS_SHADER_FLAGS")) {
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf);
for (const std::string& config : this->Configurations) {
@@ -2190,7 +2212,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(
}
// Figure out if debug information should be generated
if (cmValue sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sed);
for (const std::string& config : this->Configurations) {
@@ -2204,7 +2226,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(
}
// Figure out if optimizations should be disabled
if (cmValue sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sdo);
for (const std::string& config : this->Configurations) {
@@ -2318,26 +2340,23 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(
this->FinishWritingSource(e2, toolSettings);
if (!deployContent.empty()) {
- cmGeneratorExpression ge;
+ cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance());
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") {
+ for (auto& config : this->Configurations) {
+ if (cge->Evaluate(this->LocalGenerator, config) == "1") {
e2.WritePlatformConfigTag("DeploymentContent",
"'$(Configuration)|$(Platform)'=='" +
- this->Configurations[i] + "|" +
- this->Platform + "'",
+ config + "|" + this->Platform + "'",
"true");
} else {
e2.WritePlatformConfigTag("ExcludedFromBuild",
"'$(Configuration)|$(Platform)'=='" +
- this->Configurations[i] + "|" +
- this->Platform + "'",
+ config + "|" + this->Platform + "'",
"true");
}
}
@@ -2388,8 +2407,9 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2,
// 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())
+ if (link.empty()) {
link = cmsys::SystemTools::GetFilenameName(sf->GetFullPath());
+ }
e2.Element("Link", link);
}
@@ -2485,6 +2505,9 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
const std::string& lang = si.Source->GetLanguage();
if (lang == "C" || lang == "CXX") {
tool = "ClCompile";
+ } else if (lang == "ASM_MARMASM" &&
+ this->GlobalGenerator->IsMarmasmEnabled()) {
+ tool = "MARMASM";
} else if (lang == "ASM_MASM" &&
this->GlobalGenerator->IsMasmEnabled()) {
tool = "MASM";
@@ -2519,7 +2542,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
Elem e2(e1, tool);
bool isCSharp = (si.Source->GetLanguage() == "CSharp");
- if (isCSharp && exclude_configs.size() > 0) {
+ if (isCSharp && !exclude_configs.empty()) {
std::stringstream conditions;
bool firstConditionSet{ false };
for (const auto& ci : include_configs) {
@@ -2661,7 +2684,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
? "C"
: this->GlobalGenerator->GetLanguageFromExtension(ext.c_str());
std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf);
- const char* compileAs = 0;
+ const char* compileAs = nullptr;
if (lang != extLang) {
if (lang == "CXX") {
// force a C++ file type
@@ -2699,6 +2722,8 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
}
for (std::string const& config : this->Configurations) {
+ this->GeneratorTarget->NeedCxxModuleSupport(lang, config);
+
std::string configUpper = cmSystemTools::UpperCase(config);
std::string configDefines = defines;
std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper);
@@ -2711,6 +2736,31 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
configDefines += *ccdefs;
}
+ bool const shouldScanForModules = lang == "CXX"_s &&
+ this->GeneratorTarget->NeedDyndepForSource(lang, config, source);
+ auto const* fs =
+ this->GeneratorTarget->GetFileSetForSource(config, source);
+ const char* compileAsPerConfig = compileAs;
+ if (fs &&
+ (fs->GetType() == "CXX_MODULES"_s ||
+ fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) {
+ if (lang == "CXX"_s) {
+ if (fs->GetType() == "CXX_MODULES"_s) {
+ compileAsPerConfig = "CompileAsCppModule";
+ } else {
+ compileAsPerConfig = "CompileAsHeaderUnit";
+ }
+ } else {
+ this->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat(
+ "Target \"", this->GeneratorTarget->Target->GetName(),
+ "\" contains the source\n ", source->GetFullPath(),
+ "\nin a file set of type \"", fs->GetType(),
+ R"(" but the source is not classified as a "CXX" source.)"));
+ }
+ }
+
// We have pch state in the following situation:
// 1. We have SKIP_PRECOMPILE_HEADERS == true
// 2. We are creating the pre-compiled header
@@ -2733,13 +2783,16 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
// 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) {
+ !includes.empty() || compileAsPerConfig || 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_MARMASM" &&
+ this->GlobalGenerator->IsMarmasmEnabled()) {
+ flagtable = gg->GetMarmasmFlagTable();
} else if (srclang == "ASM_MASM" &&
this->GlobalGenerator->IsMasmEnabled()) {
flagtable = gg->GetMasmFlagTable();
@@ -2756,8 +2809,13 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cmVS10GeneratorOptions clOptions(
this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler,
flagtable, this);
- if (compileAs) {
- clOptions.AddFlag("CompileAs", compileAs);
+ if (compileAsPerConfig) {
+ clOptions.AddFlag("CompileAs", compileAsPerConfig);
+ }
+ if (shouldScanForModules) {
+ clOptions.AddFlag("ScanSourceforModuleDependencies", "true");
+ } else {
+ clOptions.AddFlag("ScanSourceforModuleDependencies", "false");
}
if (noWinRT) {
clOptions.AddFlag("CompileAsWinRT", "false");
@@ -2842,10 +2900,9 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
if (this->IsXamlSource(source->GetFullPath())) {
const std::string& fileName = source->GetFullPath();
e2.Element("DependentUpon",
- fileName.substr(0, fileName.find_last_of(".")));
+ fileName.substr(0, fileName.find_last_of('.')));
}
if (this->ProjectType == VsProjectType::csproj) {
- std::string f = source->GetFullPath();
using CsPropMap = std::map<std::string, std::string>;
CsPropMap sourceFileTags;
this->GetCSharpSourceProperties(&sf, sourceFileTags);
@@ -2886,7 +2943,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions(
if (ttype >= cmStateEnums::UTILITY) {
e1.WritePlatformConfigTag(
- "IntDir", cond, "$(Platform)\\$(Configuration)\\$(ProjectName)\\");
+ "IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)");
} else {
std::string intermediateDir = cmStrCat(
this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
@@ -3053,12 +3110,9 @@ std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes(
bool cmVisualStudio10TargetGenerator::ComputeClOptions()
{
- for (std::string const& c : this->Configurations) {
- if (!this->ComputeClOptions(c)) {
- return false;
- }
- }
- return true;
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeClOptions(c); });
}
bool cmVisualStudio10TargetGenerator::ComputeClOptions(
@@ -3274,6 +3328,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->GeneratorTarget->GetLanguages(languages, configName);
if (languages.count("C")) {
std::string flagsC;
+ this->LocalGenerator->AddLanguageFlags(
+ flagsC, this->GeneratorTarget, cmBuildStep::Compile, "C", configName);
this->LocalGenerator->AddCompileOptions(flagsC, this->GeneratorTarget,
"C", configName);
Options optC(this->LocalGenerator, Options::Compiler,
@@ -3316,9 +3372,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
}
}
- if (this->ProjectType != VsProjectType::csproj && clOptions.IsManaged()) {
+ if (this->ProjectType != VsProjectType::csproj &&
+ (clOptions.IsManaged() || clOptions.HasFlag("CLRSupport"))) {
this->Managed = true;
- std::string managedType = clOptions.GetFlag("CompileAsManaged");
+ std::string managedType = clOptions.HasFlag("CompileAsManaged")
+ ? clOptions.GetFlag("CompileAsManaged")
+ : "Mixed";
if (managedType == "Safe" || managedType == "Pure") {
// force empty calling convention if safe clr is used
clOptions.AddFlag("CallingConvention", "");
@@ -3411,7 +3470,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
// add AdditionalUsingDirectories
if (this->AdditionalUsingDirectories.count(configName) > 0) {
std::string dirs;
- for (auto u : this->AdditionalUsingDirectories[configName]) {
+ for (auto const& u : this->AdditionalUsingDirectories[configName]) {
if (!dirs.empty()) {
dirs.append(";");
}
@@ -3424,12 +3483,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
bool cmVisualStudio10TargetGenerator::ComputeRcOptions()
{
- for (std::string const& c : this->Configurations) {
- if (!this->ComputeRcOptions(c)) {
- return false;
- }
- }
- return true;
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeRcOptions(c); });
}
bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
@@ -3478,13 +3534,12 @@ 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;
+ return std::all_of(this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) {
+ return !this->GeneratorTarget->IsLanguageUsed("CUDA",
+ c) ||
+ this->ComputeCudaOptions(c);
+ });
}
bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
@@ -3570,7 +3625,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
// limitation by creating the directory and passing the flag ourselves.
pdb = this->ConvertPath(pdb, true);
ConvertToWindowsSlash(pdb);
- std::string const clFd = "-Xcompiler=\"-Fd\\\"" + pdb + "\\\"\"";
+ std::string const clFd = R"(-Xcompiler="-Fd\")" + pdb + R"(\"")";
cudaOptions.AppendFlagString("AdditionalOptions", clFd);
}
}
@@ -3654,12 +3709,9 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions()
if (!this->GlobalGenerator->IsCudaEnabled()) {
return true;
}
- for (std::string const& c : this->Configurations) {
- if (!this->ComputeCudaLinkOptions(c)) {
- return false;
- }
- }
- return true;
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeCudaLinkOptions(c); });
}
bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
@@ -3748,17 +3800,66 @@ void cmVisualStudio10TargetGenerator::WriteCudaLinkOptions(
cudaLinkOptions.OutputFlagMap();
}
+bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions()
+{
+ if (!this->GlobalGenerator->IsMarmasmEnabled()) {
+ return true;
+ }
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeMarmasmOptions(c); });
+}
+
+bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions(
+ std::string const& configName)
+{
+ cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+ auto pOptions = cm::make_unique<Options>(
+ this->LocalGenerator, Options::MarmasmCompiler, gg->GetMarmasmFlagTable());
+ Options& marmasmOptions = *pOptions;
+
+ std::string flags;
+ this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
+ cmBuildStep::Compile, "ASM_MARMASM",
+ configName);
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ "ASM_MARMASM", configName);
+
+ marmasmOptions.Parse(flags);
+
+ // Get includes for this target
+ marmasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MARMASM"));
+
+ this->MarmasmOptions[configName] = std::move(pOptions);
+ return true;
+}
+
+void cmVisualStudio10TargetGenerator::WriteMarmasmOptions(
+ Elem& e1, std::string const& configName)
+{
+ if (!this->MSTools || !this->GlobalGenerator->IsMarmasmEnabled()) {
+ return;
+ }
+ Elem e2(e1, "MARMASM");
+
+ // Preprocessor definitions and includes are shared with clOptions.
+ OptionsHelper clOptions(*(this->ClOptions[configName]), e2);
+ clOptions.OutputPreprocessorDefinitions("ASM_MARMASM");
+
+ OptionsHelper marmasmOptions(*(this->MarmasmOptions[configName]), e2);
+ marmasmOptions.OutputAdditionalIncludeDirectories("ASM_MARMASM");
+ marmasmOptions.PrependInheritedString("AdditionalOptions");
+ marmasmOptions.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;
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeMasmOptions(c); });
}
bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
@@ -3777,6 +3878,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
cmBuildStep::Compile, "ASM_MASM",
configName);
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ "ASM_MASM", configName);
masmOptions.Parse(flags);
@@ -3810,12 +3913,9 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions()
if (!this->GlobalGenerator->IsNasmEnabled()) {
return true;
}
- for (std::string const& c : this->Configurations) {
- if (!this->ComputeNasmOptions(c)) {
- return false;
- }
- }
- return true;
+ return std::all_of(
+ this->Configurations.begin(), this->Configurations.end(),
+ [this](std::string const& c) { return this->ComputeNasmOptions(c); });
}
bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
@@ -3830,6 +3930,8 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
cmBuildStep::Compile, "ASM_NASM",
configName);
+ this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
+ "ASM_NASM", configName);
flags += " -f";
flags += this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT");
nasmOptions.Parse(flags);
@@ -4452,6 +4554,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0)
// output rc compile flags <ResourceCompile></ResourceCompile>
this->WriteRCOptions(e1, c);
this->WriteCudaOptions(e1, c);
+ this->WriteMarmasmOptions(e1, c);
this->WriteMasmOptions(e1, c);
this->WriteNasmOptions(e1, c);
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 17dcecd..e00f692 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -132,6 +132,9 @@ private:
bool ComputeCudaLinkOptions(std::string const& config);
void WriteCudaLinkOptions(Elem& e1, std::string const& config);
+ bool ComputeMarmasmOptions();
+ bool ComputeMarmasmOptions(std::string const& config);
+ void WriteMarmasmOptions(Elem& e1, std::string const& config);
bool ComputeMasmOptions();
bool ComputeMasmOptions(std::string const& config);
void WriteMasmOptions(Elem& e1, std::string const& config);
@@ -149,12 +152,18 @@ private:
void OutputLinkIncremental(Elem& e1, std::string const& configName);
void WriteCustomRule(Elem& e0, cmSourceFile const* source,
cmCustomCommand const& command);
+ enum class BuildInParallel
+ {
+ No,
+ Yes,
+ };
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,
- cmCustomCommandGenerator const& ccg, bool symbolic);
+ cmCustomCommandGenerator const& ccg, bool symbolic,
+ BuildInParallel buildInParallel);
void WriteCustomRuleCSharp(Elem& e0, std::string const& config,
std::string const& commandName,
std::string const& script,
@@ -200,7 +209,6 @@ private:
void WriteStdOutEncodingUtf8(Elem& e1);
void UpdateCache();
-private:
friend class cmVS10GeneratorOptions;
using Options = cmVS10GeneratorOptions;
using OptionsMap = std::map<std::string, std::unique_ptr<Options>>;
@@ -208,6 +216,7 @@ private:
OptionsMap RcOptions;
OptionsMap CudaOptions;
OptionsMap CudaLinkOptions;
+ OptionsMap MarmasmOptions;
OptionsMap MasmOptions;
OptionsMap NasmOptions;
OptionsMap LinkOptions;
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index e6f5ece..6e98874 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -51,9 +51,9 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions(
void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
{
if (table) {
- for (int i = 0; i < FlagTableCount; ++i) {
- if (!this->FlagTable[i]) {
- this->FlagTable[i] = table;
+ for (auto& flag : this->FlagTable) {
+ if (!flag) {
+ flag = table;
break;
}
}
@@ -62,8 +62,8 @@ void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table)
void cmVisualStudioGeneratorOptions::ClearTables()
{
- for (int i = 0; i < FlagTableCount; ++i) {
- this->FlagTable[i] = nullptr;
+ for (auto& flag : this->FlagTable) {
+ flag = nullptr;
}
}
@@ -115,8 +115,7 @@ 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");
+ auto i = this->FlagMap.find("DebugType");
if (i != this->FlagMap.end()) {
if (i->second.size() == 1) {
return i->second[0] != "none";
@@ -138,22 +137,14 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const
bool cmVisualStudioGeneratorOptions::UsingUnicode() const
{
// Look for a _UNICODE definition.
- for (std::string const& di : this->Defines) {
- if (di == "_UNICODE") {
- return true;
- }
- }
- return false;
+ return std::any_of(this->Defines.begin(), this->Defines.end(),
+ [](std::string const& di) { return di == "_UNICODE"; });
}
bool cmVisualStudioGeneratorOptions::UsingSBCS() const
{
// Look for a _SBCS definition.
- for (std::string const& di : this->Defines) {
- if (di == "_SBCS") {
- return true;
- }
- }
- return false;
+ return std::any_of(this->Defines.begin(), this->Defines.end(),
+ [](std::string const& di) { return di == "_SBCS"; });
}
void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
@@ -267,8 +258,7 @@ void cmVisualStudioGeneratorOptions::ParseFinish()
}
if (this->CurrentTool == CudaCompiler) {
- std::map<std::string, FlagValue>::iterator i =
- this->FlagMap.find("CudaRuntime");
+ auto i = this->FlagMap.find("CudaRuntime");
if (i != this->FlagMap.end() && i->second.size() == 1) {
std::string& cudaRuntime = i->second[0];
if (cudaRuntime == "static") {
@@ -285,7 +275,7 @@ void cmVisualStudioGeneratorOptions::ParseFinish()
void cmVisualStudioGeneratorOptions::PrependInheritedString(
std::string const& key)
{
- std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ auto i = this->FlagMap.find(key);
if (i == this->FlagMap.end() || i->second.size() != 1) {
return;
}
@@ -295,7 +285,7 @@ void cmVisualStudioGeneratorOptions::PrependInheritedString(
void cmVisualStudioGeneratorOptions::Reparse(std::string const& key)
{
- std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ auto i = this->FlagMap.find(key);
if (i == this->FlagMap.end() || i->second.size() != 1) {
return;
}
@@ -339,7 +329,7 @@ cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag(
std::string const& key)
{
FlagValue value;
- std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key);
+ auto i = this->FlagMap.find(key);
if (i != this->FlagMap.end()) {
value = i->second;
this->FlagMap.erase(i);
@@ -373,8 +363,7 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions(
if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) {
oss << "%(" << tag << ")";
}
- std::vector<std::string>::const_iterator de =
- cmRemoveDuplicates(this->Defines);
+ auto de = cmRemoveDuplicates(this->Defines);
for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) {
// Escape the definition for the compiler.
std::string define;
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index ed4ee1d..20e2d22 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -24,6 +24,7 @@ public:
Compiler,
ResourceCompiler,
CudaCompiler,
+ MarmasmCompiler,
MasmCompiler,
NasmCompiler,
Linker,
diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx
index 2a6dfc4..4b6754e 100644
--- a/Source/cmVisualStudioSlnData.cxx
+++ b/Source/cmVisualStudioSlnData.cxx
@@ -20,33 +20,34 @@ std::string cmSlnProjectEntry::GetProjectConfiguration(
return projectConfigurationMap[solutionConfiguration];
}
-const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByGUID(
+cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByGUID(
const std::string& projectGUID) const
{
- ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID));
- if (it != ProjectsByGUID.end())
+ auto it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end()) {
return it->second;
- else
- return cm::nullopt;
+ }
+ return cm::nullopt;
}
-const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByName(
+cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByName(
const std::string& projectName) const
{
- ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName));
- if (it != ProjectNameIndex.end())
+ auto it(ProjectNameIndex.find(projectName));
+ if (it != ProjectNameIndex.end()) {
return it->second->second;
- else
- return cm::nullopt;
+ }
+ return cm::nullopt;
}
std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const
{
- ProjectStringIndex::const_iterator it(this->ProjectNameIndex.begin()),
- itEnd(this->ProjectNameIndex.end());
+ auto it(this->ProjectNameIndex.begin());
+ auto itEnd(this->ProjectNameIndex.end());
std::vector<cmSlnProjectEntry> result;
- for (; it != itEnd; ++it)
+ for (; it != itEnd; ++it) {
result.push_back(it->second->second);
+ }
return result;
}
@@ -54,9 +55,10 @@ 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;
+ auto it(ProjectsByGUID.find(projectGUID));
+ if (it != ProjectsByGUID.end()) {
+ return nullptr;
+ }
it = ProjectsByGUID
.insert(ProjectStorage::value_type(
projectGUID,
@@ -72,17 +74,20 @@ std::string cmSlnData::GetConfigurationTarget(
{
std::string solutionTarget = solutionConfiguration + "|" + platformName;
cm::optional<cmSlnProjectEntry> project = GetProjectByName(projectName);
- if (!project)
+ if (!project) {
return platformName;
+ }
std::string projectTarget = project->GetProjectConfiguration(solutionTarget);
- if (projectTarget.empty())
+ if (projectTarget.empty()) {
return platformName;
+ }
std::vector<std::string> targetElements =
cmSystemTools::SplitString(projectTarget, '|');
- if (targetElements.size() != 2)
+ if (targetElements.size() != 2) {
return platformName;
+ }
return targetElements[1];
}
diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h
index 100dd9b..5f03895 100644
--- a/Source/cmVisualStudioSlnData.h
+++ b/Source/cmVisualStudioSlnData.h
@@ -13,12 +13,12 @@
class cmSlnProjectEntry
{
public:
- cmSlnProjectEntry() {}
- cmSlnProjectEntry(const std::string& guid, const std::string& name,
- const std::string& relativePath)
- : Guid(guid)
- , Name(name)
- , RelativePath(relativePath)
+ cmSlnProjectEntry() = default;
+ cmSlnProjectEntry(std::string guid, std::string name,
+ std::string relativePath)
+ : Guid(std::move(guid))
+ , Name(std::move(name))
+ , RelativePath(std::move(relativePath))
{
}
@@ -56,10 +56,10 @@ public:
minimumVisualStudioVersion = version;
}
- const cm::optional<cmSlnProjectEntry> GetProjectByGUID(
+ cm::optional<cmSlnProjectEntry> GetProjectByGUID(
const std::string& projectGUID) const;
- const cm::optional<cmSlnProjectEntry> GetProjectByName(
+ cm::optional<cmSlnProjectEntry> GetProjectByName(
const std::string& projectName) const;
std::vector<cmSlnProjectEntry> GetProjects() const;
diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx
index feab895..71c758e 100644
--- a/Source/cmVisualStudioSlnParser.cxx
+++ b/Source/cmVisualStudioSlnParser.cxx
@@ -80,19 +80,19 @@ bool cmVisualStudioSlnParser::ParsedLine::IsKeyValuePair() const
std::string cmVisualStudioSlnParser::ParsedLine::GetArgVerbatim() const
{
- if (this->Arg.second)
+ if (this->Arg.second) {
return Quote + this->Arg.first + Quote;
- else
- return this->Arg.first;
+ }
+ return this->Arg.first;
}
const std::string& cmVisualStudioSlnParser::ParsedLine::GetValue(
size_t idxValue) const
{
- if (idxValue < this->Values.size())
+ if (idxValue < this->Values.size()) {
return this->Values[idxValue].first;
- else
- return BadString;
+ }
+ return BadString;
}
std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim(
@@ -100,12 +100,12 @@ std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim(
{
if (idxValue < this->Values.size()) {
const StringData& data = this->Values[idxValue];
- if (data.second)
+ if (data.second) {
return Quote + data.first + Quote;
- else
- return data.first;
- } else
- return BadString;
+ }
+ return data.first;
+ }
+ return BadString;
}
class cmVisualStudioSlnParser::State
@@ -140,17 +140,17 @@ private:
std::stack<FileState> Stack;
std::string EndIgnoreTag;
DataGroupSet RequestedData;
- size_t CurrentLine;
+ size_t CurrentLine = 0;
void IgnoreUntilTag(const std::string& endTag);
};
cmVisualStudioSlnParser::State::State(DataGroupSet requestedData)
: RequestedData(requestedData)
- , CurrentLine(0)
{
- if (this->RequestedData.test(DataGroupProjectDependenciesBit))
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit)) {
this->RequestedData.set(DataGroupProjectsBit);
+ }
this->Stack.push(FileStateStart);
}
@@ -206,7 +206,7 @@ bool cmVisualStudioSlnParser::State::Process(
this->Stack.push(FileStateTopLevel);
break;
case FileStateTopLevel:
- if (line.GetTag().compare("Project") == 0) {
+ if (line.GetTag() == "Project") {
if (line.GetValueCount() != 3) {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
@@ -218,14 +218,15 @@ bool cmVisualStudioSlnParser::State::Process(
return false;
}
this->Stack.push(FileStateProject);
- } else
+ } else {
this->IgnoreUntilTag("EndProject");
- } else if (line.GetTag().compare("Global") == 0) {
+ }
+ } else if (line.GetTag() == "Global") {
this->Stack.push(FileStateGlobal);
- } else if (line.GetTag().compare("VisualStudioVersion") == 0) {
+ } else if (line.GetTag() == "VisualStudioVersion") {
output.SetVisualStudioVersion(line.GetValue(0));
- } else if (line.GetTag().compare("MinimumVisualStudioVersion") == 0) {
+ } else if (line.GetTag() == "MinimumVisualStudioVersion") {
output.SetMinimumVisualStudioVersion(line.GetValue(0));
} else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
@@ -233,69 +234,75 @@ bool cmVisualStudioSlnParser::State::Process(
}
break;
case FileStateProject:
- if (line.GetTag().compare("EndProject") == 0)
+ if (line.GetTag() == "EndProject") {
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))
+ } else if (line.GetTag() == "ProjectSection") {
+ if (line.GetArg() == "ProjectDependencies" &&
+ line.GetValue(0) == "postProject") {
+ if (this->RequestedData.test(DataGroupProjectDependenciesBit)) {
this->Stack.push(FileStateProjectDependencies);
- else
+ } else {
this->IgnoreUntilTag("EndProjectSection");
- } else
+ }
+ } else {
this->IgnoreUntilTag("EndProjectSection");
+ }
} else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
}
break;
case FileStateProjectDependencies:
- if (line.GetTag().compare("EndProjectSection") == 0)
+ if (line.GetTag() == "EndProjectSection") {
this->Stack.pop();
- else if (line.IsKeyValuePair())
+ } else if (line.IsKeyValuePair()) {
// implement dependency storing here, once needed
;
- else {
+ } else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
}
break;
case FileStateGlobal:
- if (line.GetTag().compare("EndGlobal") == 0)
+ if (line.GetTag() == "EndGlobal") {
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))
+ } else if (line.GetTag() == "GlobalSection") {
+ if (line.GetArg() == "SolutionConfigurationPlatforms" &&
+ line.GetValue(0) == "preSolution") {
+ if (this->RequestedData.test(DataGroupSolutionConfigurationsBit)) {
this->Stack.push(FileStateSolutionConfigurations);
- else
+ } else {
this->IgnoreUntilTag("EndGlobalSection");
- } else if (line.GetArg().compare("ProjectConfigurationPlatforms") ==
- 0 &&
- line.GetValue(0).compare("postSolution") == 0) {
- if (this->RequestedData.test(DataGroupProjectConfigurationsBit))
+ }
+ } else if (line.GetArg() == "ProjectConfigurationPlatforms" &&
+ line.GetValue(0) == "postSolution") {
+ if (this->RequestedData.test(DataGroupProjectConfigurationsBit)) {
this->Stack.push(FileStateProjectConfigurations);
- else
+ } else {
this->IgnoreUntilTag("EndGlobalSection");
- } else if (line.GetArg().compare("NestedProjects") == 0 &&
- line.GetValue(0).compare("preSolution") == 0) {
- if (this->RequestedData.test(DataGroupSolutionFiltersBit))
+ }
+ } else if (line.GetArg() == "NestedProjects" &&
+ line.GetValue(0) == "preSolution") {
+ if (this->RequestedData.test(DataGroupSolutionFiltersBit)) {
this->Stack.push(FileStateSolutionFilters);
- else
+ } else {
this->IgnoreUntilTag("EndGlobalSection");
- } else if (this->RequestedData.test(DataGroupGenericGlobalSectionsBit))
+ }
+ } else if (this->RequestedData.test(
+ DataGroupGenericGlobalSectionsBit)) {
this->Stack.push(FileStateGlobalSection);
- else
+ } else {
this->IgnoreUntilTag("EndGlobalSection");
+ }
} else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
}
break;
case FileStateSolutionConfigurations:
- if (line.GetTag().compare("EndGlobalSection") == 0)
+ if (line.GetTag() == "EndGlobalSection") {
this->Stack.pop();
- else if (line.IsKeyValuePair()) {
+ } else if (line.IsKeyValuePair()) {
output.AddConfiguration(line.GetValue(0));
} else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
@@ -303,9 +310,9 @@ bool cmVisualStudioSlnParser::State::Process(
}
break;
case FileStateProjectConfigurations:
- if (line.GetTag().compare("EndGlobalSection") == 0)
+ if (line.GetTag() == "EndGlobalSection") {
this->Stack.pop();
- else if (line.IsKeyValuePair()) {
+ } else if (line.IsKeyValuePair()) {
std::vector<std::string> tagElements =
cmSystemTools::SplitString(line.GetTag(), '.');
if (tagElements.size() != 3 && tagElements.size() != 4) {
@@ -324,7 +331,7 @@ bool cmVisualStudioSlnParser::State::Process(
return false;
}
- if (activeBuild.compare("ActiveCfg") == 0) {
+ if (activeBuild == "ActiveCfg") {
projectEntry->AddProjectConfiguration(solutionConfiguration,
line.GetValue(0));
}
@@ -334,23 +341,23 @@ bool cmVisualStudioSlnParser::State::Process(
}
break;
case FileStateSolutionFilters:
- if (line.GetTag().compare("EndGlobalSection") == 0)
+ if (line.GetTag() == "EndGlobalSection") {
this->Stack.pop();
- else if (line.IsKeyValuePair())
+ } else if (line.IsKeyValuePair()) {
// implement filter storing here, once needed
;
- else {
+ } else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
}
break;
case FileStateGlobalSection:
- if (line.GetTag().compare("EndGlobalSection") == 0)
+ if (line.GetTag() == "EndGlobalSection") {
this->Stack.pop();
- else if (line.IsKeyValuePair())
+ } else if (line.IsKeyValuePair()) {
// implement section storing here, once needed
;
- else {
+ } else {
result.SetError(ResultErrorInputStructure, this->GetCurrentLine());
return false;
}
@@ -385,11 +392,7 @@ void cmVisualStudioSlnParser::State::IgnoreUntilTag(const std::string& endTag)
this->EndIgnoreTag = endTag;
}
-cmVisualStudioSlnParser::ResultData::ResultData()
- : Result(ResultOK)
- , ResultLine(0)
-{
-}
+cmVisualStudioSlnParser::ResultData::ResultData() = default;
void cmVisualStudioSlnParser::ResultData::Clear()
{
@@ -487,34 +490,41 @@ bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output,
{
std::string line;
// Does the .sln start with a Byte Order Mark?
- if (!this->ParseBOM(input, line, state))
+ if (!this->ParseBOM(input, line, state)) {
return false;
+ }
do {
line = cmTrimWhitespace(line);
- if (line.empty())
+ if (line.empty()) {
continue;
+ }
ParsedLine parsedLine;
switch (state.NextLineFormat()) {
case LineMultiValueTag:
- if (!this->ParseMultiValueTag(line, parsedLine, state))
+ if (!this->ParseMultiValueTag(line, parsedLine, state)) {
return false;
+ }
break;
case LineSingleValueTag:
- if (!this->ParseSingleValueTag(line, parsedLine, state))
+ if (!this->ParseSingleValueTag(line, parsedLine, state)) {
return false;
+ }
break;
case LineKeyValuePair:
- if (!this->ParseKeyValuePair(line, parsedLine, state))
+ if (!this->ParseKeyValuePair(line, parsedLine, state)) {
return false;
+ }
break;
case LineVerbatim:
parsedLine.CopyVerbatim(line);
break;
}
- if (parsedLine.IsComment())
+ if (parsedLine.IsComment()) {
continue;
- if (!state.Process(parsedLine, output, this->LastResult))
+ }
+ if (!state.Process(parsedLine, output, this->LastResult)) {
return false;
+ }
} while (state.ReadLine(input, line));
return state.Finished(this->LastResult);
}
@@ -533,8 +543,9 @@ bool cmVisualStudioSlnParser::ParseBOM(std::istream& input, std::string& line,
this->LastResult.SetError(ResultErrorReadingInput, 1);
return false;
}
- if (!this->LastResult.HadBOM)
+ if (!this->LastResult.HadBOM) {
line = bom + line; // it wasn't a BOM, prepend it to first line
+ }
return true;
}
@@ -544,9 +555,10 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line,
{
size_t idxEqualSign = line.find('=');
auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
- if (!this->ParseTag(fullTag, parsedLine, state))
+ if (!this->ParseTag(fullTag, parsedLine, state)) {
return false;
- if (idxEqualSign != line.npos) {
+ }
+ if (idxEqualSign != std::string::npos) {
size_t idxFieldStart = idxEqualSign + 1;
if (idxFieldStart < line.size()) {
size_t idxParsing = idxFieldStart;
@@ -554,24 +566,27 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line,
for (;;) {
idxParsing = line.find_first_of(",\"", idxParsing);
bool fieldOver = false;
- if (idxParsing == line.npos) {
+ if (idxParsing == std::string::npos) {
fieldOver = true;
if (inQuotes) {
this->LastResult.SetError(ResultErrorInputStructure,
state.GetCurrentLine());
return false;
}
- } else if (line[idxParsing] == ',' && !inQuotes)
+ } else if (line[idxParsing] == ',' && !inQuotes) {
fieldOver = true;
- else if (line[idxParsing] == '"')
+ } else if (line[idxParsing] == '"') {
inQuotes = !inQuotes;
+ }
if (fieldOver) {
if (!this->ParseValue(
line.substr(idxFieldStart, idxParsing - idxFieldStart),
- parsedLine))
+ parsedLine)) {
return false;
- if (idxParsing == line.npos)
+ }
+ if (idxParsing == std::string::npos) {
break; // end of last field
+ }
idxFieldStart = idxParsing + 1;
}
++idxParsing;
@@ -587,11 +602,13 @@ bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line,
{
size_t idxEqualSign = line.find('=');
auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
- if (!this->ParseTag(fullTag, parsedLine, state))
+ if (!this->ParseTag(fullTag, parsedLine, state)) {
return false;
- if (idxEqualSign != line.npos) {
- if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine))
+ }
+ if (idxEqualSign != std::string::npos) {
+ if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine)) {
return false;
+ }
}
return true;
}
@@ -601,7 +618,7 @@ bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line,
State& /*state*/)
{
size_t idxEqualSign = line.find('=');
- if (idxEqualSign == line.npos) {
+ if (idxEqualSign == std::string::npos) {
parsedLine.CopyVerbatim(line);
return true;
}
@@ -636,8 +653,9 @@ bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag,
return false;
}
parsedLine.SetQuotedArg(arg.substr(1, arg.size() - 2));
- } else
+ } else {
parsedLine.SetArg(arg);
+ }
return true;
}
@@ -645,11 +663,12 @@ bool cmVisualStudioSlnParser::ParseValue(const std::string& value,
ParsedLine& parsedLine)
{
const std::string& trimmed = cmTrimWhitespace(value);
- if (trimmed.empty())
+ if (trimmed.empty()) {
parsedLine.AddValue(trimmed);
- else if (trimmed.front() == '"' && trimmed.back() == '"')
+ } else if (trimmed.front() == '"' && trimmed.back() == '"') {
parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2));
- else
+ } else {
parsedLine.AddValue(trimmed);
+ }
return true;
}
diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h
index 60be598..0cac140 100644
--- a/Source/cmVisualStudioSlnParser.h
+++ b/Source/cmVisualStudioSlnParser.h
@@ -73,8 +73,8 @@ protected:
struct ResultData
{
- ParseResult Result;
- size_t ResultLine;
+ ParseResult Result = ResultOK;
+ size_t ResultLine = 0;
bool HadBOM;
ResultData();
diff --git a/Source/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx
index 2f71cf5..d8d0da9 100644
--- a/Source/cmVisualStudioWCEPlatformParser.cxx
+++ b/Source/cmVisualStudioWCEPlatformParser.cxx
@@ -16,9 +16,9 @@ int cmVisualStudioWCEPlatformParser::ParseVersion(const char* 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,
+ if (!cmSystemTools::ReadRegistryValue(vckey, this->VcInstallDir,
cmSystemTools::KeyWOW64_32) ||
- !cmSystemTools::ReadRegistryValue(vskey.c_str(), this->VsInstallDir,
+ !cmSystemTools::ReadRegistryValue(vskey, this->VsInstallDir,
cmSystemTools::KeyWOW64_32)) {
return 0;
}
@@ -44,13 +44,12 @@ std::string cmVisualStudioWCEPlatformParser::GetOSVersion() const
const char* cmVisualStudioWCEPlatformParser::GetArchitectureFamily() const
{
- std::map<std::string, std::string>::const_iterator it =
- this->Macros.find("ARCHFAM");
+ auto it = this->Macros.find("ARCHFAM");
if (it != this->Macros.end()) {
return it->second.c_str();
}
- return 0;
+ return nullptr;
}
void cmVisualStudioWCEPlatformParser::StartElement(const std::string& name,
diff --git a/Source/cmVisualStudioWCEPlatformParser.h b/Source/cmVisualStudioWCEPlatformParser.h
index 2fff91c..895a90d 100644
--- a/Source/cmVisualStudioWCEPlatformParser.h
+++ b/Source/cmVisualStudioWCEPlatformParser.h
@@ -16,9 +16,8 @@
class cmVisualStudioWCEPlatformParser : public cmXMLParser
{
public:
- cmVisualStudioWCEPlatformParser(const char* name = NULL)
+ cmVisualStudioWCEPlatformParser(const char* name = nullptr)
: RequiredName(name)
- , FoundRequiredName(false)
{
}
@@ -42,9 +41,9 @@ public:
}
protected:
- virtual void StartElement(const std::string& name, const char** attributes);
- void EndElement(const std::string& name);
- void CharacterDataHandler(const char* data, int length);
+ void StartElement(const std::string& name, const char** attributes) override;
+ void EndElement(const std::string& name) override;
+ void CharacterDataHandler(const char* data, int length) override;
private:
std::string FixPaths(const std::string& paths) const;
@@ -61,7 +60,7 @@ private:
std::vector<std::string> AvailablePlatforms;
const char* RequiredName;
- bool FoundRequiredName;
+ bool FoundRequiredName = false;
std::string VcInstallDir;
std::string VsInstallDir;
};
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 013a87b..468ff73 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -40,7 +40,6 @@
#include "cmCommands.h"
#include "cmDocumentation.h"
#include "cmDocumentationEntry.h"
-#include "cmDocumentationFormatter.h"
#include "cmDuration.h"
#include "cmExternalMakefileProjectGenerator.h"
#include "cmFileTimeCache.h"
@@ -71,6 +70,7 @@
# include <cm3p/curl/curl.h>
# include <cm3p/json/writer.h>
+# include "cmConfigureLog.h"
# include "cmFileAPI.h"
# include "cmGraphVizWriter.h"
# include "cmVariableWatch.h"
@@ -150,21 +150,136 @@ auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
using CommandArgument =
cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
-} // namespace
-
-static bool cmakeCheckStampFile(const std::string& stampName);
-static bool cmakeCheckStampList(const std::string& stampList);
-
#ifndef CMAKE_BOOTSTRAP
-static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
- void* ctx, const char* /*unused*/,
- const cmMakefile* /*unused*/)
+void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/,
+ void* ctx, const char* /*unused*/,
+ const cmMakefile* /*unused*/)
{
cmake* cm = reinterpret_cast<cmake*>(ctx);
cm->MarkCliAsUsed(variable);
}
#endif
+bool cmakeCheckStampFile(const std::string& stampName)
+{
+ // The stamp file does not exist. Use the stamp dependencies to
+ // determine whether it is really out of date. This works in
+ // conjunction with cmLocalVisualStudio7Generator to avoid
+ // repeatedly re-running CMake when the user rebuilds the entire
+ // solution.
+ std::string stampDepends = cmStrCat(stampName, ".depend");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
+#else
+ cmsys::ifstream fin(stampDepends.c_str());
+#endif
+ if (!fin) {
+ // The stamp dependencies file cannot be read. Just assume the
+ // build system is really out of date.
+ std::cout << "CMake is re-running because " << stampName
+ << " dependency file is missing.\n";
+ return false;
+ }
+
+ // Compare the stamp dependencies against the dependency file itself.
+ {
+ cmFileTimeCache ftc;
+ std::string dep;
+ while (cmSystemTools::GetLineFromStream(fin, dep)) {
+ int result;
+ if (!dep.empty() && dep[0] != '#' &&
+ (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
+ // The stamp depends file is older than this dependency. The
+ // build system is really out of date.
+ /* clang-format off */
+ std::cout << "CMake is re-running because " << stampName
+ << " is out-of-date.\n"
+ " the file '" << dep << "'\n"
+ " is newer than '" << stampDepends << "'\n"
+ " result='" << result << "'\n";
+ /* clang-format on */
+ return false;
+ }
+ }
+ }
+
+ // The build system is up to date. The stamp file has been removed
+ // by the VS IDE due to a "rebuild" request. Restore it atomically.
+ std::ostringstream stampTempStream;
+ stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed();
+ std::string stampTemp = stampTempStream.str();
+ {
+ // TODO: Teach cmGeneratedFileStream to use a random temp file (with
+ // multiple tries in unlikely case of conflict) and use that here.
+ cmsys::ofstream stamp(stampTemp.c_str());
+ stamp << "# CMake generation timestamp file for this directory.\n";
+ }
+ std::string err;
+ if (cmSystemTools::RenameFile(stampTemp, stampName,
+ cmSystemTools::Replace::Yes, &err) ==
+ cmSystemTools::RenameResult::Success) {
+ // CMake does not need to re-run because the stamp file is up-to-date.
+ return true;
+ }
+ cmSystemTools::RemoveFile(stampTemp);
+ cmSystemTools::Error(
+ cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err));
+ return false;
+}
+
+bool cmakeCheckStampList(const std::string& stampList)
+{
+ // If the stamp list does not exist CMake must rerun to generate it.
+ if (!cmSystemTools::FileExists(stampList)) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ "is missing.\n";
+ return false;
+ }
+ cmsys::ifstream fin(stampList.c_str());
+ if (!fin) {
+ std::cout << "CMake is re-running because generate.stamp.list "
+ "could not be read.\n";
+ return false;
+ }
+
+ // Check each stamp.
+ std::string stampName;
+ while (cmSystemTools::GetLineFromStream(fin, stampName)) {
+ if (!cmakeCheckStampFile(stampName)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+cmDocumentationEntry cmake::CMAKE_STANDARD_OPTIONS_TABLE[18] = {
+ { "-S <path-to-source>", "Explicitly specify a source directory." },
+ { "-B <path-to-build>", "Explicitly specify a build directory." },
+ { "-C <initial-cache>", "Pre-load a script to populate the cache." },
+ { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." },
+ { "-U <globbing_expr>", "Remove matching entries from CMake cache." },
+ { "-G <generator-name>", "Specify a build system generator." },
+ { "-T <toolset-name>", "Specify toolset name if supported by generator." },
+ { "-A <platform-name>", "Specify platform name if supported by generator." },
+ { "--toolchain <file>", "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." },
+ { "--install-prefix <directory>",
+ "Specify install directory [CMAKE_INSTALL_PREFIX]." },
+ { "-Wdev", "Enable developer warnings." },
+ { "-Wno-dev", "Suppress developer warnings." },
+ { "-Werror=dev", "Make developer warnings errors." },
+ { "-Wno-error=dev", "Make developer warnings not errors." },
+ { "-Wdeprecated", "Enable deprecation warnings." },
+ { "-Wno-deprecated", "Suppress deprecation warnings." },
+ { "-Werror=deprecated",
+ "Make deprecated macro and function warnings "
+ "errors." },
+ { "-Wno-error=deprecated",
+ "Make deprecated macro and function warnings "
+ "not errors." }
+};
+
cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind)
: CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory())
, FileTimeCache(cm::make_unique<cmFileTimeCache>())
@@ -196,7 +311,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind)
this->AddProjectCommands();
}
- if (mode == cmState::Project) {
+ if (mode == cmState::Project || mode == cmState::Help) {
this->LoadEnvironmentPresets();
}
@@ -1008,7 +1123,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
std::cout << "Running with debug output on for the 'find' commands "
"for package(s)";
for (auto const& v : find_pkgs) {
- std::cout << " " << v;
+ std::cout << ' ' << v;
state->SetDebugFindOutputPkgs(v);
}
std::cout << ".\n";
@@ -1021,7 +1136,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
std::vector<std::string> find_vars(cmTokenize(value, ","));
std::cout << "Running with debug output on for the variable(s)";
for (auto const& v : find_vars) {
- std::cout << " " << v;
+ std::cout << ' ' << v;
state->SetDebugFindOutputVars(v);
}
std::cout << ".\n";
@@ -1082,7 +1197,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
[](std::string const&, cmake* state) -> bool {
std::cout
<< "Not searching for unused variables given on the "
- << "command line.\n";
+ "command line.\n";
state->SetWarnUnusedCli(false);
return true;
} },
@@ -1090,7 +1205,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
"--check-system-vars", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Also check system files when warning about unused and "
- << "uninitialized variables.\n";
+ "uninitialized variables.\n";
state->SetCheckSystemVars(true);
return true;
} },
@@ -1098,7 +1213,7 @@ void cmake::SetArgs(const std::vector<std::string>& args)
"--compile-no-warning-as-error", CommandArgument::Values::Zero,
[](std::string const&, cmake* state) -> bool {
std::cout << "Ignoring COMPILE_WARNING_AS_ERROR target property and "
- << "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n";
+ "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n";
state->SetIgnoreWarningAsError(true);
return true;
} }
@@ -1497,7 +1612,7 @@ void cmake::SetTraceFile(const std::string& file)
cmSystemTools::Error(ss.str());
return;
}
- std::cout << "Trace will be written to " << file << "\n";
+ std::cout << "Trace will be written to " << file << '\n';
}
void cmake::PrintTraceFormatVersion()
@@ -1542,6 +1657,16 @@ void cmake::PrintTraceFormatVersion()
}
}
+void cmake::SetTraceRedirect(cmake* other)
+{
+ this->Trace = other->Trace;
+ this->TraceExpand = other->TraceExpand;
+ this->TraceFormatVar = other->TraceFormatVar;
+ this->TraceOnlyThisSources = other->TraceOnlyThisSources;
+
+ this->TraceRedirect = other;
+}
+
bool cmake::SetDirectoriesFromFile(const std::string& arg)
{
// Check if the argument refers to a CMakeCache.txt or
@@ -2010,12 +2135,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
}
std::vector<SaveCacheEntry> saved;
std::ostringstream warning;
- /* clang-format off */
warning
<< "You have changed variables that require your cache to be deleted.\n"
- << "Configure will be re-run and you may have to reset some variables.\n"
- << "The following variables have changed:\n";
- /* clang-format on */
+ "Configure will be re-run and you may have to reset some variables.\n"
+ "The following variables have changed:\n";
for (auto i = argsSplit.begin(); i != argsSplit.end(); ++i) {
SaveCacheEntry save;
save.key = *i;
@@ -2023,9 +2146,9 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
i++;
if (i != argsSplit.end()) {
save.value = *i;
- warning << *i << "\n";
+ warning << *i << '\n';
} else {
- warning << "\n";
+ warning << '\n';
i -= 1;
}
cmValue existingValue = this->State->GetCacheEntryValue(save.key);
@@ -2060,6 +2183,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var)
int cmake::Configure()
{
+#if !defined(CMAKE_BOOTSTRAP)
+ auto profilingRAII = this->CreateProfilingEntry("project", "configure");
+#endif
+
DiagLevel diagLevel;
if (this->DiagLevels.count("deprecated") == 1) {
@@ -2289,18 +2416,27 @@ int cmake::ActualConfigure()
// info to save time
if (!this->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();
+
+ if (!this->GetIsInTryCompile()) {
+ this->TruncateOutputLog("CMakeConfigureLog.yaml");
+ this->ConfigureLog = cm::make_unique<cmConfigureLog>(
+ cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
+ this->FileAPI->GetConfigureLogVersions());
+ }
#endif
// actually do the configure
this->GlobalGenerator->Configure();
+
+#if !defined(CMAKE_BOOTSTRAP)
+ this->ConfigureLog.reset();
+#endif
+
// 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:
@@ -2423,7 +2559,7 @@ void cmake::CreateDefaultGlobalGenerator()
auto gen = this->EvaluateDefaultGlobalGenerator();
#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW)
// This print could be unified for all platforms
- std::cout << "-- Building for: " << gen->GetName() << "\n";
+ std::cout << "-- Building for: " << gen->GetName() << '\n';
#endif
this->SetGlobalGenerator(std::move(gen));
}
@@ -2572,12 +2708,17 @@ int cmake::Generate()
if (!this->GlobalGenerator) {
return -1;
}
+
+#if !defined(CMAKE_BOOTSTRAP)
+ auto profilingRAII = this->CreateProfilingEntry("project", "generate");
+#endif
+
if (!this->GlobalGenerator->Compute()) {
return -1;
}
this->GlobalGenerator->Generate();
if (!this->GraphVizFile.empty()) {
- std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl;
+ std::cout << "Generate graphviz: " << this->GraphVizFile << '\n';
this->GenerateGraphViz(this->GraphVizFile);
}
if (this->WarnUnusedCli) {
@@ -2818,17 +2959,15 @@ void cmake::AppendGlobalGeneratorsDocumentation(
std::vector<cmDocumentationEntry>& v)
{
const auto defaultGenerator = this->EvaluateDefaultGlobalGenerator();
- const std::string defaultName = defaultGenerator->GetName();
- bool foundDefaultOne = false;
+ const auto defaultName = defaultGenerator->GetName();
+ auto foundDefaultOne = false;
for (const auto& g : this->Generators) {
- cmDocumentationEntry e;
- g->GetDocumentation(e);
- if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) {
- e.CustomNamePrefix = '*';
+ v.emplace_back(g->GetDocumentation());
+ if (!foundDefaultOne && cmHasPrefix(v.back().Name, defaultName)) {
+ v.back().CustomNamePrefix = '*';
foundDefaultOne = true;
}
- v.push_back(std::move(e));
}
}
@@ -2841,21 +2980,14 @@ void cmake::AppendExtraGeneratorsDocumentation(
// Aliases:
for (std::string const& a : eg->Aliases) {
- cmDocumentationEntry e;
- e.Name = a;
- e.Brief = doc;
- v.push_back(std::move(e));
+ v.emplace_back(cmDocumentationEntry{ a, doc });
}
// Full names:
- const std::vector<std::string> generators =
- eg->GetSupportedGlobalGenerators();
- for (std::string const& g : generators) {
- cmDocumentationEntry e;
- e.Name =
- cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name);
- e.Brief = doc;
- v.push_back(std::move(e));
+ for (std::string const& g : eg->GetSupportedGlobalGenerators()) {
+ v.emplace_back(cmDocumentationEntry{
+ cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name),
+ doc });
}
}
}
@@ -2874,7 +3006,7 @@ void cmake::PrintGeneratorList()
cmDocumentation doc;
auto generators = this->GetGeneratorsDocumentation();
doc.AppendSection("Generators", generators);
- std::cerr << "\n";
+ std::cerr << '\n';
doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr);
#endif
}
@@ -2926,7 +3058,7 @@ int cmake::CheckBuildSystem()
if (verbose) {
std::ostringstream msg;
msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument
- << "\n";
+ << '\n';
cmSystemTools::Stdout(msg.str());
}
return 1;
@@ -2946,7 +3078,7 @@ int cmake::CheckBuildSystem()
if (verbose) {
std::ostringstream msg;
msg << "Re-run cmake error reading : " << this->CheckBuildSystemArgument
- << "\n";
+ << '\n';
cmSystemTools::Stdout(msg.str());
}
// There was an error reading the file. Just rerun.
@@ -2977,9 +3109,8 @@ int cmake::CheckBuildSystem()
for (std::string const& p : products) {
if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) {
if (verbose) {
- std::ostringstream msg;
- msg << "Re-run cmake, missing byproduct: " << p << "\n";
- cmSystemTools::Stdout(msg.str());
+ cmSystemTools::Stdout(
+ cmStrCat("Re-run cmake, missing byproduct: ", p, '\n'));
}
return 1;
}
@@ -3044,7 +3175,7 @@ int cmake::CheckBuildSystem()
if (verbose) {
std::ostringstream msg;
msg << "Re-run cmake file: " << out_oldest
- << " older than: " << dep_newest << "\n";
+ << " older than: " << dep_newest << '\n';
cmSystemTools::Stdout(msg.str());
}
return 1;
@@ -3220,7 +3351,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
// permissions are questionable or some other process has deleted the
// directory
std::cerr << "Failed to change to directory " << destPath << " : "
- << std::strerror(workdir.GetLastResult()) << std::endl;
+ << std::strerror(workdir.GetLastResult()) << '\n';
return 1;
}
std::vector<std::string> args2;
@@ -3257,96 +3388,6 @@ int cmake::GetSystemInformation(std::vector<std::string>& args)
return 0;
}
-static bool cmakeCheckStampFile(const std::string& stampName)
-{
- // The stamp file does not exist. Use the stamp dependencies to
- // determine whether it is really out of date. This works in
- // conjunction with cmLocalVisualStudio7Generator to avoid
- // repeatedly re-running CMake when the user rebuilds the entire
- // solution.
- std::string stampDepends = cmStrCat(stampName, ".depend");
-#if defined(_WIN32) || defined(__CYGWIN__)
- cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary);
-#else
- cmsys::ifstream fin(stampDepends.c_str());
-#endif
- if (!fin) {
- // The stamp dependencies file cannot be read. Just assume the
- // build system is really out of date.
- std::cout << "CMake is re-running because " << stampName
- << " dependency file is missing.\n";
- return false;
- }
-
- // Compare the stamp dependencies against the dependency file itself.
- {
- cmFileTimeCache ftc;
- std::string dep;
- while (cmSystemTools::GetLineFromStream(fin, dep)) {
- int result;
- if (!dep.empty() && dep[0] != '#' &&
- (!ftc.Compare(stampDepends, dep, &result) || result < 0)) {
- // The stamp depends file is older than this dependency. The
- // build system is really out of date.
- std::cout << "CMake is re-running because " << stampName
- << " is out-of-date.\n";
- std::cout << " the file '" << dep << "'\n";
- std::cout << " is newer than '" << stampDepends << "'\n";
- std::cout << " result='" << result << "'\n";
- return false;
- }
- }
- }
-
- // The build system is up to date. The stamp file has been removed
- // by the VS IDE due to a "rebuild" request. Restore it atomically.
- std::ostringstream stampTempStream;
- stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed();
- std::string stampTemp = stampTempStream.str();
- {
- // TODO: Teach cmGeneratedFileStream to use a random temp file (with
- // multiple tries in unlikely case of conflict) and use that here.
- cmsys::ofstream stamp(stampTemp.c_str());
- stamp << "# CMake generation timestamp file for this directory.\n";
- }
- std::string err;
- if (cmSystemTools::RenameFile(stampTemp, stampName,
- cmSystemTools::Replace::Yes, &err) ==
- cmSystemTools::RenameResult::Success) {
- // CMake does not need to re-run because the stamp file is up-to-date.
- return true;
- }
- cmSystemTools::RemoveFile(stampTemp);
- cmSystemTools::Error(
- cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err));
- return false;
-}
-
-static bool cmakeCheckStampList(const std::string& stampList)
-{
- // If the stamp list does not exist CMake must rerun to generate it.
- if (!cmSystemTools::FileExists(stampList)) {
- std::cout << "CMake is re-running because generate.stamp.list "
- << "is missing.\n";
- return false;
- }
- cmsys::ifstream fin(stampList.c_str());
- if (!fin) {
- std::cout << "CMake is re-running because generate.stamp.list "
- << "could not be read.\n";
- return false;
- }
-
- // Check each stamp.
- std::string stampName;
- while (cmSystemTools::GetLineFromStream(fin, stampName)) {
- if (!cmakeCheckStampFile(stampName)) {
- return false;
- }
- }
- return true;
-}
-
void cmake::IssueMessage(MessageType t, std::string const& text,
cmListFileBacktrace const& backtrace) const
{
diff --git a/Source/cmake.h b/Source/cmake.h
index 3183577..d1f388a 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -9,7 +9,6 @@
#include <map>
#include <memory>
#include <set>
-#include <stack>
#include <string>
#include <unordered_set>
#include <utility>
@@ -18,6 +17,7 @@
#include <cm/string_view>
#include <cmext/string_view>
+#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmInstalledFile.h"
#include "cmListFileCache.h"
@@ -33,21 +33,19 @@
# include <cm3p/json/value.h>
# include "cmCMakePresetsGraph.h"
+# include "cmMakefileProfilingData.h"
#endif
+class cmConfigureLog;
class cmExternalMakefileProjectGeneratorFactory;
class cmFileAPI;
class cmFileTimeCache;
class cmGlobalGenerator;
class cmGlobalGeneratorFactory;
class cmMakefile;
-#if !defined(CMAKE_BOOTSTRAP)
-class cmMakefileProfilingData;
-#endif
class cmMessenger;
class cmVariableWatch;
struct cmBuildOptions;
-struct cmDocumentationEntry;
/** \brief Represents a cmake invocation.
*
@@ -473,13 +471,17 @@ public:
}
std::string GetTopCheckInProgressMessage()
{
- auto message = this->CheckInProgressMessages.top();
- this->CheckInProgressMessages.pop();
+ auto message = this->CheckInProgressMessages.back();
+ this->CheckInProgressMessages.pop_back();
return message;
}
void PushCheckInProgressMessage(std::string message)
{
- this->CheckInProgressMessages.emplace(std::move(message));
+ this->CheckInProgressMessages.emplace_back(std::move(message));
+ }
+ std::vector<std::string> const& GetCheckInProgressMessages() const
+ {
+ return this->CheckInProgressMessages;
}
//! Should `message` command display context.
@@ -513,10 +515,23 @@ public:
{
return this->TraceOnlyThisSources;
}
- cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; }
+ cmGeneratedFileStream& GetTraceFile()
+ {
+ if (this->TraceRedirect) {
+ return this->TraceRedirect->GetTraceFile();
+ }
+ return this->TraceFile;
+ }
void SetTraceFile(std::string const& file);
void PrintTraceFormatVersion();
+#ifndef CMAKE_BOOTSTRAP
+ cmConfigureLog* GetConfigureLog() const { return this->ConfigureLog.get(); }
+#endif
+
+ //! Use trace from another ::cmake instance.
+ void SetTraceRedirect(cmake* other);
+
bool GetWarnUninitialized() const { return this->WarnUninitialized; }
void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; }
bool GetWarnUnusedCli() const { return this->WarnUnusedCli; }
@@ -630,6 +645,24 @@ public:
#if !defined(CMAKE_BOOTSTRAP)
cmMakefileProfilingData& GetProfilingOutput();
bool IsProfilingEnabled() const;
+
+ cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry(
+ const std::string& category, const std::string& name)
+ {
+ return this->CreateProfilingEntry(
+ category, name, []() -> cm::nullopt_t { return cm::nullopt; });
+ }
+
+ template <typename ArgsFunc>
+ cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry(
+ const std::string& category, const std::string& name, ArgsFunc&& argsFunc)
+ {
+ if (this->IsProfilingEnabled()) {
+ return cm::make_optional<cmMakefileProfilingData::RAII>(
+ this->GetProfilingOutput(), category, name, argsFunc());
+ }
+ return cm::nullopt;
+ }
#endif
protected:
@@ -688,6 +721,10 @@ private:
bool TraceExpand = false;
TraceFormat TraceFormatVar = TRACE_HUMAN;
cmGeneratedFileStream TraceFile;
+ cmake* TraceRedirect = nullptr;
+#ifndef CMAKE_BOOTSTRAP
+ std::unique_ptr<cmConfigureLog> ConfigureLog;
+#endif
bool WarnUninitialized = false;
bool WarnUnusedCli = true;
bool CheckSystemVars = false;
@@ -739,7 +776,7 @@ private:
bool LogLevelWasSetViaCLI = false;
bool LogContext = false;
- std::stack<std::string> CheckInProgressMessages;
+ std::vector<std::string> CheckInProgressMessages;
std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
@@ -767,37 +804,10 @@ private:
#if !defined(CMAKE_BOOTSTRAP)
std::unique_ptr<cmMakefileProfilingData> ProfilingOutput;
#endif
-};
-#define CMAKE_STANDARD_OPTIONS_TABLE \
- { "-S <path-to-source>", "Explicitly specify a source directory." }, \
- { "-B <path-to-build>", "Explicitly specify a build directory." }, \
- { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \
- { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \
- { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \
- { "-G <generator-name>", "Specify a build system generator." }, \
- { "-T <toolset-name>", \
- "Specify toolset name if supported by generator." }, \
- { "-A <platform-name>", \
- "Specify platform name if supported by generator." }, \
- { "--toolchain <file>", \
- "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." }, \
- { "--install-prefix <directory>", \
- "Specify install directory [CMAKE_INSTALL_PREFIX]." }, \
- { "-Wdev", "Enable developer warnings." }, \
- { "-Wno-dev", "Suppress developer warnings." }, \
- { "-Werror=dev", "Make developer warnings errors." }, \
- { "-Wno-error=dev", "Make developer warnings not errors." }, \
- { "-Wdeprecated", "Enable deprecation warnings." }, \
- { "-Wno-deprecated", "Suppress deprecation warnings." }, \
- { "-Werror=deprecated", \
- "Make deprecated macro and function warnings " \
- "errors." }, \
- { \
- "-Wno-error=deprecated", \
- "Make deprecated macro and function warnings " \
- "not errors." \
- }
+public:
+ static cmDocumentationEntry CMAKE_STANDARD_OPTIONS_TABLE[18];
+};
#define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes)
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 723932e..f4e602b 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -24,7 +24,7 @@
#include "cmBuildOptions.h"
#include "cmCommandLineArgument.h"
#include "cmConsoleBuf.h"
-#include "cmDocumentationEntry.h" // IWYU pragma: keep
+#include "cmDocumentationEntry.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageMetadata.h"
@@ -46,30 +46,28 @@
namespace {
#ifndef CMAKE_BOOTSTRAP
-const char* cmDocumentationName[][2] = {
- { nullptr, " cmake - Cross-Platform Makefile Generator." },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationName = {
+ {},
+ " cmake - Cross-Platform Makefile Generator."
};
-const char* cmDocumentationUsage[][2] = {
- { nullptr,
+const cmDocumentationEntry cmDocumentationUsage[2] = {
+ { {},
" cmake [options] <path-to-source>\n"
" cmake [options] <path-to-existing-build>\n"
" cmake [options] -S <path-to-source> -B <path-to-build>" },
- { nullptr,
+ { {},
"Specify a source directory to (re-)generate a build system for "
"it in the current working directory. Specify an existing build "
- "directory to re-generate its build system." },
- { nullptr, nullptr }
+ "directory to re-generate its build system." }
};
-const char* cmDocumentationUsageNote[][2] = {
- { nullptr, "Run 'cmake --help' for more information." },
- { nullptr, nullptr }
+const cmDocumentationEntry cmDocumentationUsageNote = {
+ {},
+ "Run 'cmake --help' for more information."
};
-const char* cmDocumentationOptions[][2] = {
- CMAKE_STANDARD_OPTIONS_TABLE,
+const cmDocumentationEntry cmDocumentationOptions[31] = {
{ "--preset <preset>,--preset=<preset>", "Specify a configure preset." },
{ "--list-presets[=<type>]", "List available presets." },
{ "-E", "CMake command mode." },
@@ -113,15 +111,12 @@ const char* cmDocumentationOptions[][2] = {
{ "--compile-no-warning-as-error",
"Ignore COMPILE_WARNING_AS_ERROR property and "
"CMAKE_COMPILE_WARNING_AS_ERROR variable." },
-# if !defined(CMAKE_BOOTSTRAP)
{ "--profiling-format=<fmt>",
"Output data for profiling CMake scripts. Supported formats: "
"google-trace" },
{ "--profiling-output=<file>",
"Select an output path for the profiling data enabled through "
- "--profiling-format." },
-# endif
- { nullptr, nullptr }
+ "--profiling-format." }
};
#endif
@@ -208,7 +203,7 @@ int do_cmake(int ac, char const* const* av)
doc.addCMakeStandardDocSections();
if (doc.CheckOptions(ac, av, "--")) {
// Construct and print requested documentation.
- cmake hcm(cmake::RoleInternal, cmState::Unknown);
+ cmake hcm(cmake::RoleInternal, cmState::Help);
hcm.SetHomeDirectory("");
hcm.SetHomeOutputDirectory("");
hcm.AddCMakePaths();
@@ -228,8 +223,9 @@ int do_cmake(int ac, char const* const* av)
}
doc.AppendSection("Generators", generators);
doc.PrependSection("Options", cmDocumentationOptions);
+ doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE);
- return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ return !doc.PrintRequestedDocumentation(std::cout);
}
#else
if (ac == 1) {
@@ -307,6 +303,13 @@ int do_cmake(int ac, char const* const* av)
for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
std::string const& arg = inputArgs[i];
bool matched = false;
+
+ // Only in script mode do we stop parsing instead
+ // of preferring the last mode flag provided
+ if (arg == "--" && workingMode == cmake::SCRIPT_MODE) {
+ parsedArgs = inputArgs;
+ break;
+ }
for (auto const& m : arguments) {
if (m.matches(arg)) {
matched = true;
@@ -522,25 +525,8 @@ int do_build(int ac, char const* const* av)
if (ac >= 3) {
std::vector<std::string> inputArgs;
- bool hasPreset = false;
- for (int i = 2; i < ac; ++i) {
- if (strcmp(av[i], "--list-presets") == 0 ||
- cmHasLiteralPrefix(av[i], "--preset=") ||
- strcmp(av[i], "--preset") == 0) {
- hasPreset = true;
- break;
- }
- }
-
- if (hasPreset) {
- inputArgs.reserve(ac - 2);
- cm::append(inputArgs, av + 2, av + ac);
- } else {
- dir = cmSystemTools::CollapseFullPath(av[2]);
-
- inputArgs.reserve(ac - 3);
- cm::append(inputArgs, av + 3, av + ac);
- }
+ inputArgs.reserve(ac - 2);
+ cm::append(inputArgs, av + 2, av + ac);
decltype(inputArgs.size()) i = 0;
for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) {
@@ -555,6 +541,11 @@ int do_build(int ac, char const* const* av)
break;
}
}
+ if (!matched && i == 0) {
+ dir = cmSystemTools::CollapseFullPath(arg);
+ matched = true;
+ parsed = true;
+ }
if (!(matched && parsed)) {
dir.clear();
if (!matched) {
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 67394f9..21d0cc9 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -2,11 +2,15 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmcmd.h"
+#include <functional>
+
+#include <cm/optional>
#include <cmext/algorithm>
#include <cm3p/uv.h>
#include <fcntl.h>
+#include "cmCommandLineArgument.h"
#include "cmConsoleBuf.h"
#include "cmDuration.h"
#include "cmGlobalGenerator.h"
@@ -106,6 +110,8 @@ void CMakeCommandUsage(std::string const& program)
"(either file or directory)\n"
<< " copy_directory <dir>... destination - copy content of <dir>... "
"directories to 'destination' directory\n"
+ << " copy_directory_if_different <dir>... destination - copy changed 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"
@@ -363,6 +369,12 @@ int HandleTidy(const std::string& runCmd, const std::string& sourceFile,
std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true);
tidy_cmd.push_back(sourceFile);
+ for (auto const& arg : tidy_cmd) {
+ if (cmHasLiteralPrefix(arg, "--export-fixes=")) {
+ cmSystemTools::RemoveFile(arg.substr(cmStrLen("--export-fixes=")));
+ }
+ }
+
// clang-tidy supports working out the compile commands from a
// compile_commands.json file in a directory given by a "-p" option, or by
// passing the compiler command line arguments after --. When the latter
@@ -640,20 +652,59 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
if (args.size() > 1) {
// Copy file
if (args[1] == "copy" && args.size() > 3) {
+ using CommandArgument =
+ cmCommandLineArgument<bool(const std::string& value)>;
+
+ cm::optional<std::string> targetArg;
+ std::vector<CommandArgument> argParsers{
+ { "-t", CommandArgument::Values::One,
+ CommandArgument::setToValue(targetArg) },
+ };
+
+ std::vector<std::string> files;
+ for (decltype(args.size()) i = 2; i < args.size(); i++) {
+ const std::string& arg = args[i];
+ bool matched = false;
+ for (auto const& m : argParsers) {
+ if (m.matches(arg)) {
+ matched = true;
+ if (m.parse(arg, i, args)) {
+ break;
+ }
+ return 1; // failed to parse
+ }
+ }
+ if (!matched) {
+ files.push_back(arg);
+ }
+ }
+
// If multiple source files specified,
// then destination must be directory
- if ((args.size() > 4) &&
- (!cmSystemTools::FileIsDirectory(args.back()))) {
- std::cerr << "Error: Target (for copy command) \"" << args.back()
+ if (files.size() > 2 && !targetArg) {
+ targetArg = files.back();
+ files.pop_back();
+ }
+ if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) {
+ std::cerr << "Error: Target (for copy command) \"" << *targetArg
<< "\" is not a directory.\n";
return 1;
}
+ if (!targetArg) {
+ if (files.size() < 2) {
+ std::cerr
+ << "Error: No files or target specified (for copy command).\n";
+ return 1;
+ }
+ targetArg = files.back();
+ files.pop_back();
+ }
// If error occurs we want to continue copying next files.
bool return_value = false;
- for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
- if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) {
- std::cerr << "Error copying file \"" << arg << "\" to \""
- << args.back() << "\".\n";
+ for (auto const& file : files) {
+ if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) {
+ std::cerr << "Error copying file \"" << file << "\" to \""
+ << *targetArg << "\".\n";
return_value = true;
}
}
@@ -682,12 +733,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
return return_value;
}
- // Copy directory content
- if (args[1] == "copy_directory" && args.size() > 3) {
+ // Copy directory contents
+ if ((args[1] == "copy_directory" ||
+ args[1] == "copy_directory_if_different") &&
+ args.size() > 3) {
// If error occurs we want to continue copying next files.
bool return_value = false;
+ const bool copy_always = (args[1] == "copy_directory");
for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
- if (!cmSystemTools::CopyADirectory(arg, args.back())) {
+ if (!cmSystemTools::CopyADirectory(arg, args.back(), copy_always)) {
std::cerr << "Error copying directory from \"" << arg << "\" to \""
<< args.back() << "\".\n";
return_value = true;
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 363f473..fa38a65 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -11,21 +11,21 @@
#include "cmCTest.h"
#include "cmConsoleBuf.h"
#include "cmDocumentation.h"
+#include "cmDocumentationEntry.h"
#include "cmSystemTools.h"
#include "CTest/cmCTestLaunch.h"
#include "CTest/cmCTestScriptHandler.h"
-static const char* cmDocumentationName[][2] = {
- { nullptr, " ctest - Testing driver provided by CMake." },
- { nullptr, nullptr }
+namespace {
+const cmDocumentationEntry cmDocumentationName = {
+ {},
+ " ctest - Testing driver provided by CMake."
};
-static const char* cmDocumentationUsage[][2] = { { nullptr,
- " ctest [options]" },
- { nullptr, nullptr } };
+const cmDocumentationEntry cmDocumentationUsage = { {}, " ctest [options]" };
-static const char* cmDocumentationOptions[][2] = {
+const cmDocumentationEntry cmDocumentationOptions[74] = {
{ "--preset <preset>, --preset=<preset>",
"Read arguments from a test preset." },
{ "--list-presets", "List available test presets." },
@@ -155,9 +155,9 @@ static const char* cmDocumentationOptions[][2] = {
{ "--no-compress-output", "Do not compress test output when submitting." },
{ "--print-labels", "Print all available test labels." },
{ "--no-tests=<[error|ignore]>",
- "Regard no tests found either as 'error' or 'ignore' it." },
- { nullptr, nullptr }
+ "Regard no tests found either as 'error' or 'ignore' it." }
};
+} // anonymous namespace
// this is a test driver program for cmCTest.
int main(int argc, char const* const* argv)
@@ -186,8 +186,7 @@ int main(int argc, char const* const* argv)
if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
cmCTestLog(&inst, ERROR_MESSAGE,
- "Current working directory cannot be established."
- << std::endl);
+ "Current working directory cannot be established.\n");
return 1;
}
@@ -199,10 +198,9 @@ int main(int argc, char const* const* argv)
cmSystemTools::FileExists("DartTestfile.txt"))) {
if (argc == 1) {
cmCTestLog(&inst, ERROR_MESSAGE,
- "*********************************"
- << std::endl
- << "No test configuration file found!" << std::endl
- << "*********************************" << std::endl);
+ "*********************************\n"
+ "No test configuration file found!\n"
+ "*********************************\n");
}
cmDocumentation doc;
doc.addCTestStandardDocSections();
@@ -216,7 +214,7 @@ int main(int argc, char const* const* argv)
doc.SetSection("Name", cmDocumentationName);
doc.SetSection("Usage", cmDocumentationUsage);
doc.PrependSection("Options", cmDocumentationOptions);
- return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+ return !doc.PrintRequestedDocumentation(std::cout);
}
}
diff --git a/Source/kwsys/CONTRIBUTING.rst b/Source/kwsys/CONTRIBUTING.rst
index 32e7b83..ebd3ed3 100644
--- a/Source/kwsys/CONTRIBUTING.rst
+++ b/Source/kwsys/CONTRIBUTING.rst
@@ -27,7 +27,7 @@ copies of KWSys within dependent projects can be updated to get the changes.
Code Style
==========
-We use `clang-format`_ version **6.0** to define our style for C++ code in
+We use `clang-format`_ version **15** 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
diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
index e45db36..ccd5f6d 100644
--- a/Source/kwsys/CommandLineArguments.cxx
+++ b/Source/kwsys/CommandLineArguments.cxx
@@ -319,7 +319,7 @@ void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv)
{
int cc;
for (cc = 0; cc < argc; ++cc) {
- delete[](*argv)[cc];
+ delete[] (*argv)[cc];
}
delete[] * argv;
}
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index fa2c295..92eae41 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -390,8 +390,8 @@ bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages)
#endif
// Handle drive letters on Windows
if (expr[1] == ':' && expr[0] != '/') {
- skip = 2;
- }
+ skip = 2;
+ }
}
if (skip > 0) {
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index 45a9e6f..b25b258 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -2011,6 +2011,14 @@ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp,
return 0;
}
+#if defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wshorten-64-to-32")
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wshorten-64-to-32"
+# define KWSYSPE_CLANG_DIAG_WSHORTEN
+# endif
+#endif
+
/* Get the length of time before the given timeout time arrives.
Returns 1 if the time has already arrived, and 0 otherwise. */
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -2061,6 +2069,11 @@ static kwsysProcessTime kwsysProcessTimeGetCurrent(void)
return current;
}
+#if defined(KWSYSPE_CLANG_DIAG_WSHORTEN)
+# undef KWSYSPE_CLANG_DIAG_WSHORTEN
+# pragma clang diagnostic pop
+#endif
+
static double kwsysProcessTimeToDouble(kwsysProcessTime t)
{
return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001;
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 17e1507..0b43b4a 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -2406,8 +2406,9 @@ static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
{
if (self->CurrentInfo) {
if (self->CurrentInfo->NextEntryDelta > 0) {
- self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)(
- (char*)self->CurrentInfo + self->CurrentInfo->NextEntryDelta));
+ self->CurrentInfo =
+ ((PSYSTEM_PROCESS_INFORMATION)((char*)self->CurrentInfo +
+ self->CurrentInfo->NextEntryDelta));
return 1;
}
self->CurrentInfo = 0;
diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
index fb4e380..f2f5143 100644
--- a/Source/kwsys/RegularExpression.cxx
+++ b/Source/kwsys/RegularExpression.cxx
@@ -218,7 +218,7 @@ bool RegularExpression::deep_equal(const RegularExpression& rxp) const
20 // no Mark this point in input as start of
// #n.
// OPEN+1 is number 1, etc.
-#define CLOSE 30 // no Analogous to OPEN.
+#define CLOSE 52 // no Analogous to OPEN.
/*
* Opcode notes:
@@ -366,9 +366,9 @@ bool RegularExpression::compile(const char* exp)
}
// Allocate space.
- //#ifndef _WIN32
+ // #ifndef _WIN32
delete[] this->program;
- //#endif
+ // #endif
this->program = new char[comp.regsize];
this->progsize = static_cast<int>(comp.regsize);
@@ -1018,7 +1018,30 @@ int RegExpFind::regmatch(const char* prog)
case OPEN + 6:
case OPEN + 7:
case OPEN + 8:
- case OPEN + 9: {
+ case OPEN + 9:
+ case OPEN + 10:
+ case OPEN + 11:
+ case OPEN + 12:
+ case OPEN + 13:
+ case OPEN + 14:
+ case OPEN + 15:
+ case OPEN + 16:
+ case OPEN + 17:
+ case OPEN + 18:
+ case OPEN + 19:
+ case OPEN + 20:
+ case OPEN + 21:
+ case OPEN + 22:
+ case OPEN + 23:
+ case OPEN + 24:
+ case OPEN + 25:
+ case OPEN + 26:
+ case OPEN + 27:
+ case OPEN + 28:
+ case OPEN + 29:
+ case OPEN + 30:
+ case OPEN + 31:
+ case OPEN + 32: {
int no;
const char* save;
@@ -1046,7 +1069,30 @@ int RegExpFind::regmatch(const char* prog)
case CLOSE + 6:
case CLOSE + 7:
case CLOSE + 8:
- case CLOSE + 9: {
+ case CLOSE + 9:
+ case CLOSE + 10:
+ case CLOSE + 11:
+ case CLOSE + 12:
+ case CLOSE + 13:
+ case CLOSE + 14:
+ case CLOSE + 15:
+ case CLOSE + 16:
+ case CLOSE + 17:
+ case CLOSE + 18:
+ case CLOSE + 19:
+ case CLOSE + 20:
+ case CLOSE + 21:
+ case CLOSE + 22:
+ case CLOSE + 23:
+ case CLOSE + 24:
+ case CLOSE + 25:
+ case CLOSE + 26:
+ case CLOSE + 27:
+ case CLOSE + 28:
+ case CLOSE + 29:
+ case CLOSE + 30:
+ case CLOSE + 31:
+ case CLOSE + 32: {
int no;
const char* save;
diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
index 2709cde..1dc1dfa 100644
--- a/Source/kwsys/RegularExpression.hxx.in
+++ b/Source/kwsys/RegularExpression.hxx.in
@@ -50,7 +50,7 @@ public:
enum
{
- NSUBEXP = 10
+ NSUBEXP = 32
};
private:
@@ -456,9 +456,9 @@ inline RegularExpression::RegularExpression(const std::string& s)
*/
inline RegularExpression::~RegularExpression()
{
- //#ifndef _WIN32
+ // #ifndef _WIN32
delete[] this->program;
- //#endif
+ // #endif
}
/**
@@ -556,9 +556,9 @@ inline bool RegularExpression::is_valid() const
inline void RegularExpression::set_invalid()
{
- //#ifndef _WIN32
+ // #ifndef _WIN32
delete[] this->program;
- //#endif
+ // #endif
this->program = nullptr;
}
diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in
index 16efaef..7cef029 100644
--- a/Source/kwsys/Status.hxx.in
+++ b/Source/kwsys/Status.hxx.in
@@ -7,6 +7,16 @@
#include <string>
+/*
+ * Detect a symbol collision with the name of this class. X11 headers use
+ * `#define Status int` instead of using `typedef` which poisons any other
+ * usage of this name.
+ */
+#if defined(Status) && defined(_X11_XLIB_H_)
+# error \
+ "Status.hxx must be included *before* any X11 headers to avoid a collision with the `Status` define that is made in its API."
+#endif
+
namespace @KWSYS_NAMESPACE@ {
/** \class Status
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index e6cc48f..20e2edb 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -482,7 +482,7 @@ protected:
unsigned int); // For windows
// For Linux and Cygwin, /proc/cpuinfo formats are slightly different
- bool RetreiveInformationFromCpuInfoFile();
+ bool RetrieveInformationFromCpuInfoFile();
std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
size_t init = 0);
@@ -1520,7 +1520,7 @@ void SystemInformationImplementation::RunCPUCheck()
#elif defined(__hpux)
this->QueryHPUXProcessor();
#elif defined(__linux) || defined(__CYGWIN__)
- this->RetreiveInformationFromCpuInfoFile();
+ this->RetrieveInformationFromCpuInfoFile();
#else
this->QueryProcessor();
#endif
@@ -3435,7 +3435,7 @@ std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(
}
/** Query for the cpu status */
-bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
+bool SystemInformationImplementation::RetrieveInformationFromCpuInfoFile()
{
this->NumberOfLogicalCPU = 0;
this->NumberOfPhysicalCPU = 0;
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index a20901c..a3ab51a 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -36,6 +36,7 @@
#ifdef _WIN32
# include <cwchar>
+# include <unordered_map>
#endif
// Work-around CMake dependency scanning limitation. This must
@@ -506,16 +507,39 @@ public:
};
#ifdef _WIN32
-struct SystemToolsPathCaseCmp
+# if defined(_WIN64)
+static constexpr size_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
+static constexpr size_t FNV_PRIME = 1099511628211ULL;
+# else
+static constexpr size_t FNV_OFFSET_BASIS = 2166136261U;
+static constexpr size_t FNV_PRIME = 16777619U;
+# endif
+
+// Case insensitive Fnv1a hash
+struct SystemToolsPathCaseHash
+{
+ size_t operator()(std::string const& path) const
+ {
+ size_t hash = FNV_OFFSET_BASIS;
+ for (auto c : path) {
+ hash ^= static_cast<size_t>(std::tolower(c));
+ hash *= FNV_PRIME;
+ }
+
+ return hash;
+ }
+};
+
+struct SystemToolsPathCaseEqual
{
bool operator()(std::string const& l, std::string const& r) const
{
# ifdef _MSC_VER
- return _stricmp(l.c_str(), r.c_str()) < 0;
+ return _stricmp(l.c_str(), r.c_str()) == 0;
# elif defined(__GNUC__)
- return strcasecmp(l.c_str(), r.c_str()) < 0;
+ return strcasecmp(l.c_str(), r.c_str()) == 0;
# else
- return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0;
+ return SystemTools::Strucmp(l.c_str(), r.c_str()) == 0;
# endif
}
};
@@ -540,8 +564,12 @@ public:
bool const cache);
static std::string GetActualCaseForPathCached(std::string const& path);
static const char* GetEnvBuffered(const char* key);
- std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap;
- std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap;
+ std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
+ SystemToolsPathCaseEqual>
+ FindFileMap;
+ std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
+ SystemToolsPathCaseEqual>
+ PathCaseMap;
std::map<std::string, std::string> EnvMap;
#endif
#ifdef __CYGWIN__
@@ -2262,8 +2290,8 @@ static std::string FileInDir(const std::string& source, const std::string& dir)
return new_destination + '/' + SystemTools::GetFilenameName(source);
}
-Status SystemTools::CopyFileIfDifferent(std::string const& source,
- std::string const& destination)
+SystemTools::CopyStatus SystemTools::CopyFileIfDifferent(
+ std::string const& source, std::string const& destination)
{
// special check for a destination that is a directory
// FilesDiffer does not handle file to directory compare
@@ -2280,7 +2308,7 @@ Status SystemTools::CopyFileIfDifferent(std::string const& source,
}
}
// at this point the files must be the same so return true
- return Status::Success();
+ return CopyStatus{ Status::Success(), CopyStatus::NoPath };
}
#define KWSYS_ST_BUFFER 4096
@@ -2406,13 +2434,13 @@ bool SystemTools::TextFilesDiffer(const std::string& path1,
return false;
}
-Status SystemTools::CopyFileContentBlockwise(std::string const& source,
- std::string const& destination)
+SystemTools::CopyStatus SystemTools::CopyFileContentBlockwise(
+ std::string const& source, std::string const& destination)
{
// Open files
kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary);
if (!fin) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath };
}
// try and remove the destination file so that read only destination files
@@ -2424,7 +2452,7 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source,
kwsys::ofstream fout(destination.c_str(),
std::ios::out | std::ios::trunc | std::ios::binary);
if (!fout) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath };
}
// This copy loop is very sensitive on certain platforms with
@@ -2453,10 +2481,10 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source,
fout.close();
if (!fout) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath };
}
- return Status::Success();
+ return CopyStatus{ Status::Success(), CopyStatus::NoPath };
}
/**
@@ -2471,13 +2499,13 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source,
* - The underlying filesystem does not support file cloning
* - An unspecified error occurred
*/
-Status SystemTools::CloneFileContent(std::string const& source,
- std::string const& destination)
+SystemTools::CopyStatus SystemTools::CloneFileContent(
+ std::string const& source, std::string const& destination)
{
#if defined(__linux) && defined(FICLONE)
int in = open(source.c_str(), O_RDONLY);
if (in < 0) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath };
}
SystemTools::RemoveFile(destination);
@@ -2485,14 +2513,14 @@ Status SystemTools::CloneFileContent(std::string const& source,
int out =
open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (out < 0) {
- Status status = Status::POSIX_errno();
+ CopyStatus status{ Status::POSIX_errno(), CopyStatus::DestPath };
close(in);
return status;
}
- Status status = Status::Success();
+ CopyStatus status{ Status::Success(), CopyStatus::NoPath };
if (ioctl(out, FICLONE, in) < 0) {
- status = Status::POSIX_errno();
+ status = CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath };
}
close(in);
close(out);
@@ -2504,40 +2532,41 @@ Status SystemTools::CloneFileContent(std::string const& source,
// be updated by `copy_file_if_different` and `copy_file`.
if (copyfile(source.c_str(), destination.c_str(), nullptr,
COPYFILE_METADATA | COPYFILE_CLONE) < 0) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath };
}
# if KWSYS_CXX_HAS_UTIMENSAT
// utimensat is only available on newer Unixes and macOS 10.13+
if (utimensat(AT_FDCWD, destination.c_str(), nullptr, 0) < 0) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath };
}
# else
// fall back to utimes
if (utimes(destination.c_str(), nullptr) < 0) {
- return Status::POSIX_errno();
+ return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath };
}
# endif
- return Status::Success();
+ return CopyStatus{ Status::Success(), CopyStatus::NoPath };
#else
(void)source;
(void)destination;
- return Status::POSIX(ENOSYS);
+ return CopyStatus{ Status::POSIX(ENOSYS), CopyStatus::NoPath };
#endif
}
/**
* Copy a file named by "source" to the file named by "destination".
*/
-Status SystemTools::CopyFileAlways(std::string const& source,
- std::string const& destination)
+SystemTools::CopyStatus SystemTools::CopyFileAlways(
+ std::string const& source, std::string const& destination)
{
- Status status;
+ CopyStatus status;
mode_t perm = 0;
Status perms = SystemTools::GetPermissions(source, perm);
std::string real_destination = destination;
if (SystemTools::FileIsDirectory(source)) {
- status = SystemTools::MakeDirectory(destination);
+ status = CopyStatus{ SystemTools::MakeDirectory(destination),
+ CopyStatus::DestPath };
if (!status.IsSuccess()) {
return status;
}
@@ -2562,7 +2591,8 @@ Status SystemTools::CopyFileAlways(std::string const& source,
// Create destination directory
if (!destination_dir.empty()) {
- status = SystemTools::MakeDirectory(destination_dir);
+ status = CopyStatus{ SystemTools::MakeDirectory(destination_dir),
+ CopyStatus::DestPath };
if (!status.IsSuccess()) {
return status;
}
@@ -2578,13 +2608,15 @@ Status SystemTools::CopyFileAlways(std::string const& source,
}
}
if (perms) {
- status = SystemTools::SetPermissions(real_destination, perm);
+ status = CopyStatus{ SystemTools::SetPermissions(real_destination, perm),
+ CopyStatus::DestPath };
}
return status;
}
-Status SystemTools::CopyAFile(std::string const& source,
- std::string const& destination, bool always)
+SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
+ std::string const& destination,
+ bool always)
{
if (always) {
return SystemTools::CopyFileAlways(source, destination);
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index acce015..56b65fd 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -566,11 +566,34 @@ public:
const mode_t* mode = nullptr);
/**
+ * Represent the result of a file copy operation.
+ * This is the result 'Status' and, if the operation failed,
+ * an indication of whether the error occurred on the source
+ * or destination path.
+ */
+ struct CopyStatus : public Status
+ {
+ enum WhichPath
+ {
+ NoPath,
+ SourcePath,
+ DestPath,
+ };
+ CopyStatus() = default;
+ CopyStatus(Status s, WhichPath p)
+ : Status(s)
+ , Path(p)
+ {
+ }
+ WhichPath Path = NoPath;
+ };
+
+ /**
* Copy the source file to the destination file only
* if the two files differ.
*/
- static Status CopyFileIfDifferent(std::string const& source,
- std::string const& destination);
+ static CopyStatus CopyFileIfDifferent(std::string const& source,
+ std::string const& destination);
/**
* Compare the contents of two files. Return true if different
@@ -588,13 +611,13 @@ public:
/**
* Blockwise copy source to destination file
*/
- static Status CopyFileContentBlockwise(std::string const& source,
- std::string const& destination);
+ static CopyStatus CopyFileContentBlockwise(std::string const& source,
+ std::string const& destination);
/**
* Clone the source file to the destination file
*/
- static Status CloneFileContent(std::string const& source,
- std::string const& destination);
+ static CopyStatus CloneFileContent(std::string const& source,
+ std::string const& destination);
/**
* Return true if the two files are the same file
@@ -604,16 +627,17 @@ public:
/**
* Copy a file.
*/
- static Status CopyFileAlways(std::string const& source,
- std::string const& destination);
+ static CopyStatus CopyFileAlways(std::string const& source,
+ std::string const& destination);
/**
* Copy a file. If the "always" argument is true the file is always
* copied. If it is false, the file is copied only if it is new or
* has changed.
*/
- static Status CopyAFile(std::string const& source,
- std::string const& destination, bool always = true);
+ static CopyStatus CopyAFile(std::string const& source,
+ std::string const& destination,
+ bool always = true);
/**
* Copy content directory to another directory with all files and
diff --git a/Source/kwsys/kwsysPrivate.h b/Source/kwsys/kwsysPrivate.h
index dd9c127..2f5c2fa 100644
--- a/Source/kwsys/kwsysPrivate.h
+++ b/Source/kwsys/kwsysPrivate.h
@@ -27,7 +27,7 @@
*/
# define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE)
# define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x)
-# define KWSYS_NAMESPACE_STRING1(x) # x
+# define KWSYS_NAMESPACE_STRING1(x) #x
#else
# error "kwsysPrivate.h included multiple times."
diff --git a/Source/kwsys/testConfigure.cxx b/Source/kwsys/testConfigure.cxx
index a3c2ed3..4a34e1c 100644
--- a/Source/kwsys/testConfigure.cxx
+++ b/Source/kwsys/testConfigure.cxx
@@ -22,7 +22,7 @@ static bool testFallthrough(int n)
return r == 2;
}
-int testConfigure(int, char* [])
+int testConfigure(int, char*[])
{
bool res = true;
res = testFallthrough(1) && res;
diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx
index 4b7ddf0..f9b826d 100644
--- a/Source/kwsys/testConsoleBuf.cxx
+++ b/Source/kwsys/testConsoleBuf.cxx
@@ -743,7 +743,7 @@ static int testConsole()
#endif
-int testConsoleBuf(int, char* [])
+int testConsoleBuf(int, char*[])
{
int ret = 0;
diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx
index 79bdc98..8c73af2 100644
--- a/Source/kwsys/testDirectory.cxx
+++ b/Source/kwsys/testDirectory.cxx
@@ -19,7 +19,7 @@ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
#include <testSystemTools.h>
-static int _doLongPathTest()
+static int doLongPathTest()
{
using namespace kwsys;
static const int LONG_PATH_THRESHOLD = 512;
@@ -77,7 +77,7 @@ static int _doLongPathTest()
return res;
}
-static int _nonExistentDirectoryTest()
+static int nonExistentDirectoryTest()
{
using namespace kwsys;
int res = 0;
@@ -105,7 +105,7 @@ static int _nonExistentDirectoryTest()
return res;
}
-static int _copyDirectoryTest()
+static int copyDirectoryTest()
{
using namespace kwsys;
const std::string source(TEST_SYSTEMTOOLS_BINARY_DIR
@@ -136,8 +136,7 @@ static int _copyDirectoryTest()
return 0;
}
-int testDirectory(int, char* [])
+int testDirectory(int, char*[])
{
- return _doLongPathTest() + _nonExistentDirectoryTest() +
- _copyDirectoryTest();
+ return doLongPathTest() + nonExistentDirectoryTest() + copyDirectoryTest();
}
diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx
index 1d605cb..3acb6c8 100644
--- a/Source/kwsys/testEncoding.cxx
+++ b/Source/kwsys/testEncoding.cxx
@@ -266,7 +266,7 @@ static int testToWindowsExtendedPath()
#endif
}
-int testEncoding(int, char* [])
+int testEncoding(int, char*[])
{
const char* loc = setlocale(LC_ALL, "");
if (loc) {
diff --git a/Source/kwsys/testFStream.cxx b/Source/kwsys/testFStream.cxx
index 3325e20..9897a58 100644
--- a/Source/kwsys/testFStream.cxx
+++ b/Source/kwsys/testFStream.cxx
@@ -136,7 +136,7 @@ static int testBOMIO()
return 0;
}
-int testFStream(int, char* [])
+int testFStream(int, char*[])
{
int ret = 0;
diff --git a/Source/kwsys/testStatus.cxx b/Source/kwsys/testStatus.cxx
index 0a767a8..9cadada 100644
--- a/Source/kwsys/testStatus.cxx
+++ b/Source/kwsys/testStatus.cxx
@@ -16,7 +16,7 @@ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
# include <windows.h>
#endif
-int testStatus(int, char* [])
+int testStatus(int, char*[])
{
bool res = true;
{
diff --git a/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx
index 4f0c522..7ae94ff 100644
--- a/Source/kwsys/testSystemInformation.cxx
+++ b/Source/kwsys/testSystemInformation.cxx
@@ -19,7 +19,7 @@
#define printMethod3(info, m, unit) \
std::cout << #m << ": " << info.m << " " << unit << "\n"
-int testSystemInformation(int, char* [])
+int testSystemInformation(int, char*[])
{
std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index 487da8d..8afcb68 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -1209,7 +1209,7 @@ static bool CheckSplitString()
return ret;
}
-int testSystemTools(int, char* [])
+int testSystemTools(int, char*[])
{
bool res = true;
diff --git a/Templates/MSBuild/FlagTables/v10_MARMASM.json b/Templates/MSBuild/FlagTables/v10_MARMASM.json
new file mode 100644
index 0000000..90668ba
--- /dev/null
+++ b/Templates/MSBuild/FlagTables/v10_MARMASM.json
@@ -0,0 +1,140 @@
+[
+ {
+ "name": "16BitThumbInstructions",
+ "switch": "16",
+ "comment": "Assemble source as 16-bit Thumb instructions.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "32BitArmInstructions",
+ "switch": "32",
+ "comment": "Assemble source as 32-bit ARM instructions.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "CoffThumb2Only",
+ "switch": "coff_thumb2_only",
+ "comment": "Allow only Thumb-2 code.",
+ "value": "true",
+ "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": "Errors",
+ "switch": "errors",
+ "comment": "Redirect error and warning messages.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "FunctionOverride",
+ "switch": "funcOverride",
+ "comment": "Emit function overriding support for the specified function.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "GenerateDebugInformation",
+ "switch": "g",
+ "comment": "Generate debugging information.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "Machine",
+ "switch": "machine",
+ "comment": "Specify the machine type to set in the PE header.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "NoEsc",
+ "switch": "noesc",
+ "comment": "Ignore C-style escaped special characters.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoLogo",
+ "switch": "nologo",
+ "comment": "Suppress the copyright banner.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "NoWarn",
+ "switch": "nowarn",
+ "comment": "Disable all warning messages.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "ObjectFile",
+ "switch": "o",
+ "comment": "Specify the name of the object (output) file.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "ItBlocks",
+ "switch": "oldit",
+ "comment": "Generate ARMv7-style IT blocks.",
+ "value": "true",
+ "flags": []
+ },
+ {
+ "name": "SourceLink",
+ "switch": "sourcelink",
+ "comment": "Specify the configuration file that contains a simple mapping of local file paths to URLs for source files to display in the debugger.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ },
+ {
+ "name": "CommandLineArgumentsViaFile",
+ "switch": "via",
+ "comment": "Read extra command-line arguments from the specified file.",
+ "value": "",
+ "flags": [
+ "UserValue"
+ ]
+ }
+]
diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json
index c76c040..4f2dce8 100644
--- a/Templates/MSBuild/FlagTables/v142_CL.json
+++ b/Templates/MSBuild/FlagTables/v142_CL.json
@@ -56,6 +56,13 @@
"flags": []
},
{
+ "name": "CLRSupport",
+ "switch": "clr:netcore",
+ "comment": ".NET Core Runtime Support",
+ "value": "NetCore",
+ "flags": []
+ },
+ {
"name": "WarningLevel",
"switch": "W0",
"comment": "Turn Off All Warnings",
diff --git a/Templates/MSBuild/FlagTables/v143_CL.json b/Templates/MSBuild/FlagTables/v143_CL.json
index 993fbf1..119e171 100644
--- a/Templates/MSBuild/FlagTables/v143_CL.json
+++ b/Templates/MSBuild/FlagTables/v143_CL.json
@@ -56,6 +56,13 @@
"flags": []
},
{
+ "name": "CLRSupport",
+ "switch": "clr:netcore",
+ "comment": ".NET Core Runtime Support",
+ "value": "NetCore",
+ "flags": []
+ },
+ {
"name": "WarningLevel",
"switch": "W0",
"comment": "Turn Off All Warnings",
diff --git a/Templates/MSBuild/nasm.targets b/Templates/MSBuild/nasm.targets
index eeeb613..ba12085 100644
--- a/Templates/MSBuild/nasm.targets
+++ b/Templates/MSBuild/nasm.targets
@@ -30,7 +30,7 @@
</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)"/>
+ <NASM Condition="'@(NASM)' != '' and '%(NASM.ExcludedFromBuild)' != 'true'" Inputs="%(NASM.Inputs)" OutputFormat="%(NASM.OutputFormat)" Outputswitch="%(NASM.Outputswitch)" tasmmode="%(NASM.tasmmode)" 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>
diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
index 0702ab5..3de9ef7 100644
--- a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt
@@ -83,3 +83,8 @@ get_target_property(_res imp INCLUDE_DIRECTORIES)
if (_res)
message(SEND_ERROR "include_directories populated the INCLUDE_DIRECTORIES target property")
endif()
+
+# Test selecting lexicographically-later header of same name via include order.
+# Xcode 'USE_HEADERMAP = YES' breaks this.
+add_library(same STATIC same.c same_one/same.h same_two/same.h)
+target_include_directories(same PRIVATE same_two)
diff --git a/Tests/CMakeCommands/target_include_directories/same.c b/Tests/CMakeCommands/target_include_directories/same.c
new file mode 100644
index 0000000..8fb8d29
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/same.c
@@ -0,0 +1,7 @@
+#include "same.h"
+#ifndef CORRECT_SAME_H_INCLUDED
+# error "Correct \"same.h\" not included!"
+#endif
+void same(void)
+{
+}
diff --git a/Tests/CMakeCommands/target_include_directories/same_one/same.h b/Tests/CMakeCommands/target_include_directories/same_one/same.h
new file mode 100644
index 0000000..e71fe01
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/same_one/same.h
@@ -0,0 +1 @@
+#error "Wrong \"same.h\" included!"
diff --git a/Tests/CMakeCommands/target_include_directories/same_two/same.h b/Tests/CMakeCommands/target_include_directories/same_two/same.h
new file mode 100644
index 0000000..91ac63c
--- /dev/null
+++ b/Tests/CMakeCommands/target_include_directories/same_two/same.h
@@ -0,0 +1 @@
+#define CORRECT_SAME_H_INCLUDED
diff --git a/Tests/CMakeGUI/CatchShow.h b/Tests/CMakeGUI/CatchShow.h
index 0254c15..7d370b6 100644
--- a/Tests/CMakeGUI/CatchShow.h
+++ b/Tests/CMakeGUI/CatchShow.h
@@ -30,12 +30,13 @@ 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);
+ QMetaObject::invokeMethod(
+ obj,
+ [this, func, d]() {
+ ++this->m_count;
+ func(d);
+ },
+ Qt::QueuedConnection);
}
};
}
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
index e044794..2647fef 100644
--- a/Tests/CMakeLib/testArgumentParser.cxx
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -365,7 +365,7 @@ bool testArgumentParserStaticBool()
} // namespace
-int testArgumentParser(int /*unused*/, char* /*unused*/ [])
+int testArgumentParser(int /*unused*/, char* /*unused*/[])
{
if (!testArgumentParserDynamic()) {
std::cout << "While executing testArgumentParserDynamic().\n";
diff --git a/Tests/CMakeLib/testCMExtAlgorithm.cxx b/Tests/CMakeLib/testCMExtAlgorithm.cxx
index b8319c3..c909f24 100644
--- a/Tests/CMakeLib/testCMExtAlgorithm.cxx
+++ b/Tests/CMakeLib/testCMExtAlgorithm.cxx
@@ -110,7 +110,7 @@ void testAppend()
}
}
-int testCMExtAlgorithm(int /*unused*/, char* /*unused*/ [])
+int testCMExtAlgorithm(int /*unused*/, char* /*unused*/[])
{
testAppend();
diff --git a/Tests/CMakeLib/testCMExtEnumSet.cxx b/Tests/CMakeLib/testCMExtEnumSet.cxx
index dbb0a54..ecf6d11 100644
--- a/Tests/CMakeLib/testCMExtEnumSet.cxx
+++ b/Tests/CMakeLib/testCMExtEnumSet.cxx
@@ -203,7 +203,7 @@ void testEdition()
}
}
-int testCMExtEnumSet(int /*unused*/, char* /*unused*/ [])
+int testCMExtEnumSet(int /*unused*/, char* /*unused*/[])
{
testDeclaration();
testIteration();
diff --git a/Tests/CMakeLib/testCMExtMemory.cxx b/Tests/CMakeLib/testCMExtMemory.cxx
index d8932ce..0143515 100644
--- a/Tests/CMakeLib/testCMExtMemory.cxx
+++ b/Tests/CMakeLib/testCMExtMemory.cxx
@@ -55,7 +55,7 @@ bool testReferenceCast()
}
}
-int testCMExtMemory(int /*unused*/, char* /*unused*/ [])
+int testCMExtMemory(int /*unused*/, char* /*unused*/[])
{
if (!testReferenceCast()) {
return 1;
diff --git a/Tests/CMakeLib/testCMFilesystemPath.cxx b/Tests/CMakeLib/testCMFilesystemPath.cxx
index 579ba99..52cb43a 100644
--- a/Tests/CMakeLib/testCMFilesystemPath.cxx
+++ b/Tests/CMakeLib/testCMFilesystemPath.cxx
@@ -969,7 +969,7 @@ bool testNonMemberFunctions()
}
}
-int testCMFilesystemPath(int /*unused*/, char* /*unused*/ [])
+int testCMFilesystemPath(int /*unused*/, char* /*unused*/[])
{
int result = 0;
diff --git a/Tests/CMakeLib/testCTestBinPacker.cxx b/Tests/CMakeLib/testCTestBinPacker.cxx
index 772f417..038ceea 100644
--- a/Tests/CMakeLib/testCTestBinPacker.cxx
+++ b/Tests/CMakeLib/testCTestBinPacker.cxx
@@ -275,7 +275,7 @@ static bool TestExpectedPackResult(const ExpectedPackResult& expected)
return true;
}
-int testCTestBinPacker(int /*unused*/, char* /*unused*/ [])
+int testCTestBinPacker(int /*unused*/, char* /*unused*/[])
{
int retval = 0;
diff --git a/Tests/CMakeLib/testCTestResourceGroups.cxx b/Tests/CMakeLib/testCTestResourceGroups.cxx
index 776d65d..b68301f 100644
--- a/Tests/CMakeLib/testCTestResourceGroups.cxx
+++ b/Tests/CMakeLib/testCTestResourceGroups.cxx
@@ -127,7 +127,7 @@ static bool TestExpectedParseResult(const ExpectedParseResult& expected)
return true;
}
-int testCTestResourceGroups(int /*unused*/, char* /*unused*/ [])
+int testCTestResourceGroups(int /*unused*/, char* /*unused*/[])
{
int retval = 0;
diff --git a/Tests/CMakeLib/testFindPackageCommand.cxx b/Tests/CMakeLib/testFindPackageCommand.cxx
index bfd429f..30749be 100644
--- a/Tests/CMakeLib/testFindPackageCommand.cxx
+++ b/Tests/CMakeLib/testFindPackageCommand.cxx
@@ -14,7 +14,7 @@
std::cout << "FAILED: " << (m) << "\n"; \
failed = 1
-int testFindPackageCommand(int /*unused*/, char* /*unused*/ [])
+int testFindPackageCommand(int /*unused*/, char* /*unused*/[])
{
int failed = 0;
diff --git a/Tests/CMakeLib/testGeneratedFileStream.cxx b/Tests/CMakeLib/testGeneratedFileStream.cxx
index de44a0b..ad1c9e5 100644
--- a/Tests/CMakeLib/testGeneratedFileStream.cxx
+++ b/Tests/CMakeLib/testGeneratedFileStream.cxx
@@ -10,7 +10,7 @@
std::cout << "FAILED: " << (m1) << (m2) << "\n"; \
failed = 1
-int testGeneratedFileStream(int /*unused*/, char* /*unused*/ [])
+int testGeneratedFileStream(int /*unused*/, char* /*unused*/[])
{
int failed = 0;
cmGeneratedFileStream gm;
diff --git a/Tests/CMakeLib/testJSONHelpers.cxx b/Tests/CMakeLib/testJSONHelpers.cxx
index 2cd3f75..053c163 100644
--- a/Tests/CMakeLib/testJSONHelpers.cxx
+++ b/Tests/CMakeLib/testJSONHelpers.cxx
@@ -457,7 +457,7 @@ bool testRequired()
}
}
-int testJSONHelpers(int /*unused*/, char* /*unused*/ [])
+int testJSONHelpers(int /*unused*/, char* /*unused*/[])
{
if (!testInt()) {
return 1;
diff --git a/Tests/CMakeLib/testOptional.cxx b/Tests/CMakeLib/testOptional.cxx
index 2007fff..785f031 100644
--- a/Tests/CMakeLib/testOptional.cxx
+++ b/Tests/CMakeLib/testOptional.cxx
@@ -760,7 +760,7 @@ static bool testMemoryRange(std::vector<Event>& expected)
return true;
}
-int testOptional(int /*unused*/, char* /*unused*/ [])
+int testOptional(int /*unused*/, char* /*unused*/[])
{
int retval = 0;
diff --git a/Tests/CMakeLib/testRange.cxx b/Tests/CMakeLib/testRange.cxx
index 4efe98e..36c1e18 100644
--- a/Tests/CMakeLib/testRange.cxx
+++ b/Tests/CMakeLib/testRange.cxx
@@ -15,7 +15,7 @@
} \
} while (false)
-int testRange(int /*unused*/, char* /*unused*/ [])
+int testRange(int /*unused*/, char* /*unused*/[])
{
std::vector<int> const testData = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
diff --git a/Tests/CMakeLib/testString.cxx b/Tests/CMakeLib/testString.cxx
index 5a9cad1..af34a2f 100644
--- a/Tests/CMakeLib/testString.cxx
+++ b/Tests/CMakeLib/testString.cxx
@@ -1163,7 +1163,7 @@ static bool testStability()
return true;
}
-int testString(int /*unused*/, char* /*unused*/ [])
+int testString(int /*unused*/, char* /*unused*/[])
{
if (!testConstructDefault()) {
return 1;
diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx
index 1e6b611..1bb23df 100644
--- a/Tests/CMakeLib/testStringAlgorithms.cxx
+++ b/Tests/CMakeLib/testStringAlgorithms.cxx
@@ -6,13 +6,15 @@
#include <iostream>
#include <sstream>
#include <string>
+#include <type_traits>
+#include <utility>
#include <vector>
#include <cm/string_view>
#include "cmStringAlgorithms.h"
-int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
+int testStringAlgorithms(int /*unused*/, char* /*unused*/[])
{
int failed = 0;
@@ -144,6 +146,28 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
d -= val;
assert_ok((d < div) && (d > -div), "cmStrCat double");
}
+ {
+ std::string val;
+ std::string expect;
+ val.reserve(50 * cmStrLen("cmStrCat move ") + 1);
+ auto data = val.data();
+ auto capacity = val.capacity();
+ bool moved = true;
+ for (int i = 0; i < 100; i++) {
+ if (i % 2 == 0) {
+ val = cmStrCat(std::move(val), "move ");
+ expect += "move ";
+ } else {
+ val = cmStrCat("cmStrCat ", std::move(val));
+ expect = "cmStrCat " + std::move(expect);
+ }
+ if (val.data() != data || val.capacity() != capacity) {
+ moved = false;
+ }
+ }
+ assert_ok(moved, "cmStrCat move");
+ assert_string(val, expect, "cmStrCat move");
+ }
// ----------------------------------------------------------------------
// Test cmWrap
diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx
index 92f5275..754205e 100644
--- a/Tests/CMakeLib/testSystemTools.cxx
+++ b/Tests/CMakeLib/testSystemTools.cxx
@@ -25,7 +25,7 @@
} \
} while (false)
-int testSystemTools(int /*unused*/, char* /*unused*/ [])
+int testSystemTools(int /*unused*/, char* /*unused*/[])
{
int failed = 0;
// ----------------------------------------------------------------------
diff --git a/Tests/CMakeLib/testUTF8.cxx b/Tests/CMakeLib/testUTF8.cxx
index 1bf88cf..fc0b539 100644
--- a/Tests/CMakeLib/testUTF8.cxx
+++ b/Tests/CMakeLib/testUTF8.cxx
@@ -164,7 +164,7 @@ static bool is_invalid(const char* s)
return true;
}
-int testUTF8(int /*unused*/, char* /*unused*/ [])
+int testUTF8(int /*unused*/, char* /*unused*/[])
{
int result = 0;
for (test_utf8_entry const* e = good_entry; e->n; ++e) {
diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx
index fd88e24..0bdd44c 100644
--- a/Tests/CMakeLib/testUVRAII.cxx
+++ b/Tests/CMakeLib/testUVRAII.cxx
@@ -30,8 +30,7 @@ static bool testAsyncShutdown()
std::thread([&] {
std::this_thread::sleep_for(std::chrono::seconds(2));
signal.send();
- })
- .detach();
+ }).detach();
if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
index 760fa29..f9ed6af 100644
--- a/Tests/CMakeLib/testUVStreambuf.cxx
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -404,12 +404,13 @@ static bool testUVStreambufRead(
<< std::endl;
goto end;
}
- uv_timer_start(timer,
- [](uv_timer_t* handle) {
- auto buf = static_cast<cmUVStreambuf*>(handle->data);
- buf->close();
- },
- 0, 0);
+ 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;
diff --git a/Tests/CMakeLib/testVisualStudioSlnParser.cxx b/Tests/CMakeLib/testVisualStudioSlnParser.cxx
index 7fdba9a..c1bf3d4 100644
--- a/Tests/CMakeLib/testVisualStudioSlnParser.cxx
+++ b/Tests/CMakeLib/testVisualStudioSlnParser.cxx
@@ -27,7 +27,7 @@ static bool parsedRight(cmVisualStudioSlnParser& parser,
return false;
}
-int testVisualStudioSlnParser(int, char* [])
+int testVisualStudioSlnParser(int, char*[])
{
cmVisualStudioSlnParser parser;
diff --git a/Tests/CMakeLib/testXMLParser.cxx b/Tests/CMakeLib/testXMLParser.cxx
index 8617cc1..32ee3ec 100644
--- a/Tests/CMakeLib/testXMLParser.cxx
+++ b/Tests/CMakeLib/testXMLParser.cxx
@@ -4,7 +4,7 @@
#include "cmXMLParser.h"
-int testXMLParser(int /*unused*/, char* /*unused*/ [])
+int testXMLParser(int /*unused*/, char* /*unused*/[])
{
// TODO: Derive from parser and check attributes.
cmXMLParser parser;
diff --git a/Tests/CMakeLib/testXMLSafe.cxx b/Tests/CMakeLib/testXMLSafe.cxx
index dc62eb9..f0bd9c9 100644
--- a/Tests/CMakeLib/testXMLSafe.cxx
+++ b/Tests/CMakeLib/testXMLSafe.cxx
@@ -25,7 +25,7 @@ static test_pair const pairs[] = {
{ nullptr, nullptr }
};
-int testXMLSafe(int /*unused*/, char* /*unused*/ [])
+int testXMLSafe(int /*unused*/, char* /*unused*/[])
{
int result = 0;
for (test_pair const* p = pairs; p->in; ++p) {
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 6e35df9..c22f704 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -271,14 +271,6 @@ if(BUILD_TESTING)
find_package(Qt5Widgets QUIET NO_MODULE)
endif()
- if(NOT CMake_TEST_EXTERNAL_CMAKE)
- add_subdirectory(CMakeLib)
- endif()
- add_subdirectory(CMakeOnly)
- add_subdirectory(RunCMake)
-
- add_subdirectory(FindPackageModeMakefileTest)
-
# Collect a list of all test build directories.
set(TEST_BUILD_DIRS)
@@ -342,6 +334,27 @@ if(BUILD_TESTING)
endif()
endif()
+ if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT)
+ if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND
+ ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
+ (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ set(CMake_TEST_XCODE_SWIFT 1)
+ endif()
+ endif()
+ endif()
+ if(NOT DEFINED CMake_TEST_Swift)
+ if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+ set(CMake_TEST_Swift 1)
+ endif()
+ endif()
+
+ if(NOT DEFINED CMake_TEST_OBJC)
+ if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
+ set(CMake_TEST_OBJC 1)
+ endif()
+ endif()
+
# Use 1500 or CTEST_TEST_TIMEOUT for long test timeout value,
# whichever is greater.
set(CMAKE_LONG_TEST_TIMEOUT 1500)
@@ -352,6 +365,14 @@ if(BUILD_TESTING)
set(CMAKE_LONG_TEST_TIMEOUT 1500)
endif()
+ if(NOT CMake_TEST_EXTERNAL_CMAKE)
+ add_subdirectory(CMakeLib)
+ endif()
+ add_subdirectory(CMakeOnly)
+ add_subdirectory(RunCMake)
+
+ add_subdirectory(FindPackageModeMakefileTest)
+
add_test(NAME CMake.Copyright
COMMAND ${CMAKE_CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMakeCopyright.cmake)
@@ -380,16 +401,7 @@ if(BUILD_TESTING)
ADD_TEST_MACRO(MissingSourceFile MissingSourceFile)
set_tests_properties(MissingSourceFile PROPERTIES
PASS_REGULAR_EXPRESSION "CMake Error at CMakeLists.txt:3 \\(add_executable\\):[ \r\n]*Cannot find source file:[ \r\n]*DoesNotExist/MissingSourceFile.c")
- if(CMake_TEST_XCODE_VERSION AND CMAKE_OSX_SDKVERSION AND CMAKE_OSX_SDKPRODUCT)
- if((NOT CMake_TEST_XCODE_VERSION VERSION_LESS 6.1) AND
- ((NOT CMAKE_OSX_SDKPRODUCT STREQUAL "Mac OS X") OR
- (NOT CMAKE_OSX_SDKVERSION VERSION_LESS 10.10)))
- if(CMAKE_GENERATOR STREQUAL "Xcode")
- set(CMake_TEST_XCODE_SWIFT 1)
- endif()
- endif()
- endif()
- if(CMAKE_Swift_COMPILER OR CMake_TEST_XCODE_SWIFT)
+ if(CMake_TEST_Swift)
ADD_TEST_MACRO(SwiftOnly SwiftOnly)
if(CMake_TEST_XCODE_SWIFT)
ADD_TEST_MACRO(SwiftMix SwiftMix)
@@ -432,6 +444,11 @@ if(BUILD_TESTING)
endif()
endif()
+ if(CMake_TEST_OBJC)
+ add_subdirectory(ObjC)
+ add_subdirectory(ObjCXX)
+ endif()
+
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
ADD_TEST_MACRO(CSharpOnly CSharpOnly)
if(NOT CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
@@ -1463,6 +1480,7 @@ if(BUILD_TESTING)
GTK2
Iconv
ICU
+ ImageMagick
Intl
Jasper
JNI
@@ -1521,8 +1539,11 @@ if(BUILD_TESTING)
add_subdirectory(GoogleTest)
endif()
- if(CMake_TEST_FindPython OR CMake_TEST_FindPython_NumPy
+ if(CMake_TEST_FindPython OR CMake_TEST_FindPython_SABIModule OR CMake_TEST_FindPython_NumPy
OR CMake_TEST_FindPython_Conda OR CMake_TEST_FindPython_IronPython OR CMake_TEST_FindPython_PyPy)
+ if (CMake_TEST_FindPython AND CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
+ set(CMake_TEST_FindPython_SABIModule TRUE)
+ endif()
add_subdirectory(FindPython)
endif()
@@ -2144,10 +2165,16 @@ if(BUILD_TESTING)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/MFC")
endif()
+ if(MSVC AND NOT MSVC_VERSION LESS 1700
+ AND (CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
+ )
+ ADD_TEST_MACRO(VSMARMASM VSMARMASM)
+ endif()
+
if(MSVC AND NOT MSVC_VERSION LESS 1310
AND (NOT CMAKE_GENERATOR MATCHES "Visual Studio 9 "
OR CMAKE_SIZEOF_VOID_P EQUAL 4)
- AND (NOT CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
+ AND (NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
)
ADD_TEST_MACRO(VSMASM VSMASM)
endif()
@@ -2500,9 +2527,6 @@ if(BUILD_TESTING)
-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()
diff --git a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
index 0907d03..c990eb4 100644
--- a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
+++ b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
@@ -96,8 +96,8 @@ foreach(VTEST ALSA ARMADILLO BZIP2 CUPS CURL EXPAT FREETYPE GETTEXT GIT HG
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)
+foreach(VTEST BISON Boost BZIP2 CUDA DOXYGEN FLEX GIF GTK2
+ HDF5 JPEG LibArchive LIBLZMA OPENSCENEGRAPH Ruby RUBY SWIG Protobuf ZLIB)
check_version_string(${VTEST} ${VTEST}_VERSION)
endforeach()
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index bd2dd7e..16e631b 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -32,16 +32,6 @@ AddCMakeTest(ProcessorCount "-DKWSYS_TEST_EXE=$<TARGET_FILE:cmsysTestsCxx>")
AddCMakeTest(PushCheckState "")
AddCMakeTest(While "")
-AddCMakeTest(FileDownload "")
-set_tests_properties(CMake.FileDownload PROPERTIES
- PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
- FAIL_REGULAR_EXPRESSION "Unexpected status|incorrectly interpreted"
- )
-AddCMakeTest(FileDownloadBadHash "")
-set_property(TEST CMake.FileDownloadBadHash PROPERTY
- WILL_FAIL TRUE
- )
-
AddCMakeTest(FileUpload "")
set(EndStuff_PreArgs
diff --git a/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in b/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in
deleted file mode 100644
index 64b45ed..0000000
--- a/Tests/CMakeTests/FileDownloadBadHashTest.cmake.in
+++ /dev/null
@@ -1,13 +0,0 @@
-if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
- set(slash /)
-endif()
-set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
-set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
-
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT 2
- STATUS status
- EXPECTED_HASH SHA1=5555555555555555555555555555555555555555
- )
diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in
deleted file mode 100644
index 255909d..0000000
--- a/Tests/CMakeTests/FileDownloadTest.cmake.in
+++ /dev/null
@@ -1,229 +0,0 @@
-# We do not contact any real URLs, but do try a bogus one.
-# Remove any proxy configuration that may change behavior.
-unset(ENV{http_proxy})
-unset(ENV{https_proxy})
-
-set(timeout 4)
-
-if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
- set(slash /)
-endif()
-set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
-set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
-
-# Beware Windows asynchronous file/directory removal, rename and then
-# remove the renamed dir so we can be certain the dir isn't there when
-# we get to the file() commands below
-if(EXISTS "${dir}")
- file(RENAME ${dir} "${dir}_beingRemoved")
- file(REMOVE_RECURSE "${dir}_beingRemoved")
-endif()
-
-function(__reportIfWrongStatus statusPair expectedStatusCode)
- list(GET statusPair 0 statusCode)
- if(NOT statusCode EQUAL expectedStatusCode)
- message(SEND_ERROR
- "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}")
- endif()
-endfunction()
-
-message(STATUS "FileDownload:1")
-file(DOWNLOAD
- ${url}
- ${dir}/file1.png
- TIMEOUT ${timeout}
- STATUS status
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:2")
-file(DOWNLOAD
- ${url}
- ${dir}/file2.png
- TIMEOUT ${timeout}
- STATUS status
- SHOW_PROGRESS
- )
-__reportIfWrongStatus("${status}" 0)
-
-# Two calls in a row, exactly the same arguments.
-# Since downloaded file should exist already for 2nd call,
-# the 2nd call will short-circuit and return early...
-#
-if(EXISTS ${dir}/file3.png)
- file(REMOVE ${dir}/file3.png)
-endif()
-
-message(STATUS "FileDownload:3")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:4")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:5")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:6")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:7")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:8")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:9")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:10")
-file(DOWNLOAD
- ${url}
- ${dir}/file3.png
- TIMEOUT ${timeout}
- STATUS status
- EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
- )
-__reportIfWrongStatus("${status}" 0)
-# Print status because we check its message too
-message(STATUS "${status}")
-
-# do not use proxy for lookup of invalid site (DNS failure by proxy looks
-# different than DNS failure without proxy)
-set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid")
-message(STATUS "FileDownload:11")
-file(DOWNLOAD
- badhostname.invalid
- ${dir}/file11.png
- TIMEOUT 30
- STATUS status
- )
-message(STATUS "${status}")
-__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name
-
-message(STATUS "FileDownload:12")
-set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png")
-if(EXISTS "${absFile}")
- file(RENAME ${absFile} "${absFile}_beingRemoved")
- file(REMOVE "${absFile}_beingRemoved")
-endif()
-file(DOWNLOAD
- ${url}
- file12.png
- TIMEOUT ${timeout}
- EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
- STATUS status
- )
-__reportIfWrongStatus("${status}" 0)
-if(NOT EXISTS file12.png)
- message(SEND_ERROR "file12.png not downloaded: ${status}")
-endif()
-
-message(STATUS "FileDownload:13")
-file(DOWNLOAD
- ${url}
- TIMEOUT ${timeout}
- STATUS status
- )
-__reportIfWrongStatus("${status}" 0)
-if(EXISTS TIMEOUT)
- file(REMOVE TIMEOUT)
- message(SEND_ERROR "TIMEOUT argument was incorrectly interpreted as a filename")
-endif()
-message(STATUS "${status}")
-
-message(STATUS "FileDownload:14")
-file(DOWNLOAD
- ${url}
- ${dir}/file14.bin
- TIMEOUT ${timeout}
- STATUS status
- RANGE_START 0
- EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:15")
-file(DOWNLOAD
- ${url}
- ${dir}/file15.bin
- TIMEOUT ${timeout}
- STATUS status
- RANGE_END 50
- EXPECTED_MD5 8592e5665b839b5d23825dc84c135b61
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:16")
-file(DOWNLOAD
- ${url}
- ${dir}/file16.bin
- TIMEOUT ${timeout}
- STATUS status
- RANGE_START 10
- RANGE_END 50
- EXPECTED_MD5 36cd52681e6c6c8fef85fcd9e86fc30d
- )
-__reportIfWrongStatus("${status}" 0)
-
-message(STATUS "FileDownload:17")
-file(DOWNLOAD
- ${url}
- ${dir}/file17.bin
- TIMEOUT ${timeout}
- STATUS status
- RANGE_START 0
- RANGE_END 50
- RANGE_START 60
- RANGE_END 100
- EXPECTED_MD5 c5c9e74e82d493dd901eecccd659cebc
- )
-__reportIfWrongStatus("${status}" 0)
diff --git a/Tests/CMakeTests/FileDownloadInput.png b/Tests/CMakeTests/FileUploadInput.png
index 9ab565a..9ab565a 100644
--- a/Tests/CMakeTests/FileDownloadInput.png
+++ b/Tests/CMakeTests/FileUploadInput.png
Binary files differ
diff --git a/Tests/CMakeTests/FileUploadTest.cmake.in b/Tests/CMakeTests/FileUploadTest.cmake.in
index 0e6f080..7725041 100644
--- a/Tests/CMakeTests/FileUploadTest.cmake.in
+++ b/Tests/CMakeTests/FileUploadTest.cmake.in
@@ -9,7 +9,7 @@ endif()
file(MAKE_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@/uploads")
-set(filename "@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
+set(filename "@CMAKE_CURRENT_SOURCE_DIR@/FileUploadInput.png")
if(NOT "@CMAKE_CURRENT_BINARY_DIR@" MATCHES "^/")
set(slash /)
endif()
diff --git a/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake
new file mode 100644
index 0000000..eb2eb42
--- /dev/null
+++ b/Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake
@@ -0,0 +1,22 @@
+string(TIMESTAMP output "%z")
+
+STRING(LENGTH output output_length)
+
+message("~${output}~")
+
+set(expected_output_length 6)
+
+if(NOT(${output_length} EQUAL ${expected_output_length}))
+ message(FATAL_ERROR "expected ${expected_output_length} entries in output with all specifiers; found ${output_length}")
+endif()
+
+string(SUBSTRING ${output} 0 1 output0)
+string(SUBSTRING ${output} 4 1 output4)
+
+if(NOT((${output0} STREQUAL "-") OR (${output0} STREQUAL "+")))
+ message(FATAL_ERROR "expected output[0] equ '+' or '-'; found: '${output0}'")
+endif()
+
+if(NOT((${output4} STREQUAL "0") OR (${output4} STREQUAL "5")))
+ message(FATAL_ERROR "expected output[4] equ '0' or '5'; found: '${output4}'")
+endif()
diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in
index 154afa7..5f8b111 100644
--- a/Tests/CMakeTests/StringTest.cmake.in
+++ b/Tests/CMakeTests/StringTest.cmake.in
@@ -44,6 +44,8 @@ set(TIMESTAMP-IncompleteSpecifier-RESULT 0)
set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~")
set(TIMESTAMP-AllSpecifiers-RESULT 0)
set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~")
+set(TIMESTAMP-TimeZone-RESULT 0)
+set(TIMESTAMP-TimeZone-STDERR "~[-,+][0-9][0-9][0-9][0-9]~")
set(TIMESTAMP-MonthWeekNames-RESULT 0)
set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~")
set(TIMESTAMP-UnixTime-RESULT 0)
@@ -75,6 +77,7 @@ check_cmake_test(String
TIMESTAMP-IncompleteSpecifier
TIMESTAMP-AllSpecifiers
TIMESTAMP-MonthWeekNames
+ TIMESTAMP-TimeZone
TIMESTAMP-UnixTime
)
diff --git a/Tests/CSharpLinkFromCxx/.gitattributes b/Tests/CSharpLinkFromCxx/.gitattributes
index cf9d355..57a39049 100644
--- a/Tests/CSharpLinkFromCxx/.gitattributes
+++ b/Tests/CSharpLinkFromCxx/.gitattributes
@@ -1 +1 @@
-UsefulManagedCppClass.* -format.clang-format-6.0
+UsefulManagedCppClass.* -format.clang-format
diff --git a/Tests/CheckFortran.cmake b/Tests/CheckFortran.cmake
index 36293f5..1e943a1 100644
--- a/Tests/CheckFortran.cmake
+++ b/Tests/CheckFortran.cmake
@@ -33,6 +33,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
RESULT_VARIABLE result
)
include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran/result.cmake OPTIONAL)
+ # FIXME: Replace with message(CONFIGURE_LOG) when CMake version is high enough.
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"
diff --git a/Tests/CheckSourceTree/check.cmake b/Tests/CheckSourceTree/check.cmake
index c2e3529..655e419 100644
--- a/Tests/CheckSourceTree/check.cmake
+++ b/Tests/CheckSourceTree/check.cmake
@@ -3,6 +3,15 @@ if(DEFINED ENV{CTEST_REAL_HOME})
set(ENV{HOME} "$ENV{CTEST_REAL_HOME}")
endif()
+file(GLOB known_files
+ "${CMake_SOURCE_DIR}/Tests/Java/hs_err_pid*.log"
+ "${CMake_SOURCE_DIR}/Tests/JavaExportImport/InstallExport/hs_err_pid*.log"
+ "${CMake_SOURCE_DIR}/Tests/JavaNativeHeaders/hs_err_pid*.log"
+ )
+if(known_files)
+ file(REMOVE ${known_files})
+endif()
+
execute_process(
COMMAND "${GIT_EXECUTABLE}" status
WORKING_DIRECTORY "${CMake_SOURCE_DIR}"
diff --git a/Tests/CheckSwift.cmake b/Tests/CheckSwift.cmake
index 099c298..86ea603 100644
--- a/Tests/CheckSwift.cmake
+++ b/Tests/CheckSwift.cmake
@@ -42,6 +42,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckSwift/result.cmake
OPTIONAL)
+ # FIXME: Replace with message(CONFIGURE_LOG) when CMake version is high enough.
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"
diff --git a/Tests/CompileFeatures/.gitattributes b/Tests/CompileFeatures/.gitattributes
index 95a8956..83da28d 100644
--- a/Tests/CompileFeatures/.gitattributes
+++ b/Tests/CompileFeatures/.gitattributes
@@ -1,2 +1,2 @@
# Do not format a source containing C++11 '>>' syntax as C++98.
-cxx_right_angle_brackets.cpp -format.clang-format-6.0
+cxx_right_angle_brackets.cpp -format.clang-format
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index f3d3a73..17f4408 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -374,3 +374,16 @@ else()
target_link_libraries(CompileFeaturesGenex3 PRIVATE std_11_iface)
target_compile_definitions(CompileFeaturesGenex3 PRIVATE ${genex_test_defs} ALLOW_LATER_STANDARDS=1)
endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"
+ AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30
+ # The MSVC 14.29.30133 toolset supports C++20,
+ # but MSBuild puts the flags in the wrong order.
+ OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30129 AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ )
+ )
+ add_library(msvc_permissive msvc_permissive.cxx)
+ target_compile_features(msvc_permissive PRIVATE cxx_std_20)
+ # The `-std:c++20` flag implies `-permissive-`. Test passing `-permissive` afterward.
+ target_compile_options(msvc_permissive PRIVATE -permissive)
+endif()
diff --git a/Tests/CompileFeatures/cxx_attribute_deprecated.cpp b/Tests/CompileFeatures/cxx_attribute_deprecated.cpp
index 8faeca8..5482db8 100644
--- a/Tests/CompileFeatures/cxx_attribute_deprecated.cpp
+++ b/Tests/CompileFeatures/cxx_attribute_deprecated.cpp
@@ -1,5 +1,8 @@
-[[deprecated]] int foo() { return 0; }
+[[deprecated]] int foo()
+{
+ return 0;
+}
int someFunc()
{
diff --git a/Tests/CompileFeatures/cxx_attributes.cpp b/Tests/CompileFeatures/cxx_attributes.cpp
index 1434317..543a3f5 100644
--- a/Tests/CompileFeatures/cxx_attributes.cpp
+++ b/Tests/CompileFeatures/cxx_attributes.cpp
@@ -1,5 +1,5 @@
-void unusedFunc[[noreturn]]()
+void unusedFunc [[noreturn]] ()
{
throw 1;
}
diff --git a/Tests/CompileFeatures/msvc_permissive.cxx b/Tests/CompileFeatures/msvc_permissive.cxx
new file mode 100644
index 0000000..a8f2ff3
--- /dev/null
+++ b/Tests/CompileFeatures/msvc_permissive.cxx
@@ -0,0 +1,9 @@
+#if !defined(_MSVC_LANG) || _MSVC_LANG < 202002L
+# error "This source must be compiled with MSVC as C++20 or later."
+#endif
+// Test a construct that is allowed by MSVC only with 'cl -permissive'.
+enum class X
+{
+ Y = 1
+};
+int array[X::Y];
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
index 669c412..0041b07 100644
--- a/Tests/Cuda/CMakeLists.txt
+++ b/Tests/Cuda/CMakeLists.txt
@@ -16,6 +16,7 @@ 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.StaticRuntimePlusToolkit StaticRuntimePlusToolkit)
add_cuda_test_macro(Cuda.Complex CudaComplex)
add_cuda_test_macro(Cuda.ProperLinkFlags ProperLinkFlags)
@@ -24,10 +25,4 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
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/SeparableCompCXXOnly/main.cpp b/Tests/Cuda/SeparableCompCXXOnly/main.cpp
index 8135246..ed913ff 100644
--- a/Tests/Cuda/SeparableCompCXXOnly/main.cpp
+++ b/Tests/Cuda/SeparableCompCXXOnly/main.cpp
@@ -1,5 +1,5 @@
-int main(int, char const* [])
+int main(int, char const*[])
{
return 0;
}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
index 61a3190..088be3b 100644
--- a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -15,16 +15,19 @@ 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)
+# Verify the CUDA Toolkit has static libraries
+if(TARGET CUDA::curand_static AND
+ TARGET CUDA::nppif_static)
#shared runtime with static toolkit libraries
add_library(StaticToolkit SHARED static.cpp)
+ target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION")
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
+
+ #shared runtime with mixed toolkit libraries
add_library(MixedToolkit SHARED mixed.cpp)
+ target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION")
target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
target_link_libraries(MixedToolkit PUBLIC CUDA::cudart)
endif()
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
index 2a4da22..d958c3a 100644
--- a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
@@ -1,19 +1,28 @@
#ifdef _WIN32
# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
IMPORT int shared_version();
+
+#ifdef HAS_STATIC_VERSION
+IMPORT int static_version();
+#else
int static_version()
{
return 0;
}
+#endif
+
+#ifdef HAS_MIXED_VERSION
+IMPORT int mixed_version();
+#else
int mixed_version()
{
return 0;
}
-#else
-int shared_version();
-int static_version();
-int mixed_version();
#endif
int main()
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
index df6c392..bb3dadf 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -15,15 +15,23 @@ 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)
+# Verify the CUDA Toolkit has static libraries
+if(TARGET CUDA::curand_static AND
+ TARGET CUDA::nppif_static)
+ #static runtime with static toolkit libraries
+ add_library(StaticToolkit SHARED static.cpp)
+ target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION")
+ 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)
+ #static runtime with mixed toolkit libraries
+ add_library(MixedToolkit SHARED mixed.cpp)
+ target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION")
+ target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+ target_link_libraries(MixedToolkit PUBLIC CUDA::cudart_static)
+endif()
add_executable(StaticRuntimePlusToolkit main.cpp)
-target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
+target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit
+ $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+ $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
index 95872f0..fdd7b53 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
@@ -1,6 +1,12 @@
// 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.
@@ -25,7 +31,7 @@
} \
} while (0)
-int curand_main()
+EXPORT int curand_main()
{
size_t n = 100;
size_t i;
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
index 5a09f8e..d958c3a 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
@@ -1,8 +1,29 @@
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
-int shared_version();
-int static_version();
-int mixed_version();
+IMPORT int shared_version();
+
+#ifdef HAS_STATIC_VERSION
+IMPORT int static_version();
+#else
+int static_version()
+{
+ return 0;
+}
+#endif
+
+#ifdef HAS_MIXED_VERSION
+IMPORT int mixed_version();
+#else
+int mixed_version()
+{
+ return 0;
+}
+#endif
int main()
{
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
index a05140d..6de6886 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
@@ -1,8 +1,16 @@
-int curand_main();
-int nppif_main();
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
-int mixed_version()
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int mixed_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
index 2871090..ac5341c 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
@@ -1,6 +1,12 @@
// 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>
@@ -8,7 +14,7 @@
#include <cuda_runtime_api.h>
#include <nppi_filtering_functions.h>
-int nppif_main()
+EXPORT int nppif_main()
{
/**
* 8-bit unsigned single-channel 1D row convolution.
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
index 9967b66..f3c3dbc 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
@@ -1,8 +1,16 @@
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
int curand_main();
int nppif_main();
-int shared_version()
+EXPORT int shared_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
index ca7eb4c..6932fa3 100644
--- a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
@@ -1,8 +1,16 @@
-int curand_main();
-int nppif_main();
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
-int static_version()
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int static_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/Cuda/Toolkit/CMakeLists.txt b/Tests/Cuda/Toolkit/CMakeLists.txt
index 4df29fa..b67aa32 100644
--- a/Tests/Cuda/Toolkit/CMakeLists.txt
+++ b/Tests/Cuda/Toolkit/CMakeLists.txt
@@ -22,6 +22,9 @@ 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_GREATER 11)
+ list(APPEND cuda_libs nvJitLink)
+endif()
if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
list(APPEND cuda_libs nvgraph)
endif()
@@ -30,6 +33,8 @@ endif()
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")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -41,6 +46,9 @@ if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
list(APPEND npp_libs nppicom)
endif()
foreach (cuda_lib IN LISTS npp_libs)
+ if(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
+ endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "The CUDA::${cuda_lib} target was expected but couldn't be found")
endif()
diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt
index 39634ac..db08076 100644
--- a/Tests/CudaOnly/CMakeLists.txt
+++ b/Tests/CudaOnly/CMakeLists.txt
@@ -10,6 +10,7 @@ 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.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit)
add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98)
add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit)
add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang)
@@ -28,12 +29,6 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
add_cuda_test_macro(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag)
endif()
-# The CUDA only ships the shared version of the toolkit libraries
-# on windows
-if(NOT WIN32)
- add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit)
-endif()
-
add_cuda_test_macro(CudaOnly.DeviceLTO CudaOnlyDeviceLTO)
if(MSVC)
diff --git a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
index 17069e3..ca73b1a 100644
--- a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
+++ b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt
@@ -15,6 +15,9 @@ get_property(sep_comp TARGET CUDASeparateLibA PROPERTY CUDA_SEPARABLE_COMPILATIO
if(NOT sep_comp)
message(FATAL_ERROR "CUDA_SEPARABLE_COMPILATION not initialized")
endif()
+set_target_properties(CUDASeparateLibA
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
unset(CMAKE_CUDA_SEPARABLE_COMPILATION)
if(CMAKE_CUDA_SIMULATE_ID STREQUAL "MSVC")
@@ -26,17 +29,24 @@ if(CMAKE_CUDA_SIMULATE_ID STREQUAL "MSVC")
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
+#Have file4 and file5 in different shared libraries so that we
+#verify that hidden visibility is passed to the device linker.
+#Otherwise we will get a segv when trying to run the executable
#
-add_library(CUDASeparateLibB STATIC file4.cu file5.cu)
+add_library(CUDASeparateLibB SHARED file4.cu)
target_compile_features(CUDASeparateLibB PRIVATE cuda_std_11)
target_link_libraries(CUDASeparateLibB PRIVATE CUDASeparateLibA)
-set_target_properties(CUDASeparateLibA
- CUDASeparateLibB
- PROPERTIES CUDA_SEPARABLE_COMPILATION ON
- POSITION_INDEPENDENT_CODE ON)
+add_library(CUDASeparateLibC SHARED file5.cu)
+target_compile_features(CUDASeparateLibC PRIVATE cuda_std_11)
+target_link_libraries(CUDASeparateLibC PRIVATE CUDASeparateLibA)
+
+set_target_properties(CUDASeparateLibB
+ CUDASeparateLibC
+ PROPERTIES
+ CUDA_SEPARABLE_COMPILATION ON
+ POSITION_INDEPENDENT_CODE ON
+ CUDA_VISIBILITY_PRESET hidden
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/main")
add_subdirectory(main)
diff --git a/Tests/CudaOnly/SeparateCompilation/file1.h b/Tests/CudaOnly/SeparateCompilation/file1.h
index ff1945c..1cedc20 100644
--- a/Tests/CudaOnly/SeparateCompilation/file1.h
+++ b/Tests/CudaOnly/SeparateCompilation/file1.h
@@ -1,5 +1,14 @@
#pragma once
+
+#ifdef _WIN32
+# define EXPORT __declspec(dllexport)
+# define IMPORT __declspec(dllimport)
+#else
+# define EXPORT __attribute__((__visibility__("default")))
+# define IMPORT
+#endif
+
struct result_type
{
int input;
diff --git a/Tests/CudaOnly/SeparateCompilation/file4.cu b/Tests/CudaOnly/SeparateCompilation/file4.cu
index 2e3e01e..cc24a46 100644
--- a/Tests/CudaOnly/SeparateCompilation/file4.cu
+++ b/Tests/CudaOnly/SeparateCompilation/file4.cu
@@ -15,7 +15,7 @@ static __global__ void file4_kernel(result_type& r, int x)
result_type_dynamic rd = file2_func(x);
}
-int file4_launch_kernel(int x)
+EXPORT int file4_launch_kernel(int x)
{
result_type r;
file4_kernel<<<1, 1>>>(r, x);
diff --git a/Tests/CudaOnly/SeparateCompilation/file5.cu b/Tests/CudaOnly/SeparateCompilation/file5.cu
index fee8e9e..38cbeb2 100644
--- a/Tests/CudaOnly/SeparateCompilation/file5.cu
+++ b/Tests/CudaOnly/SeparateCompilation/file5.cu
@@ -15,7 +15,7 @@ static __global__ void file5_kernel(result_type& r, int x)
result_type_dynamic rd = file2_func(x);
}
-int file5_launch_kernel(int x)
+EXPORT int file5_launch_kernel(int x)
{
result_type r;
file5_kernel<<<1, 1>>>(r, x);
diff --git a/Tests/CudaOnly/SeparateCompilation/main/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/main/CMakeLists.txt
index c181078..ce066c6 100644
--- a/Tests/CudaOnly/SeparateCompilation/main/CMakeLists.txt
+++ b/Tests/CudaOnly/SeparateCompilation/main/CMakeLists.txt
@@ -1,5 +1,5 @@
add_executable(CudaOnlySeparateCompilation main.cu)
-target_link_libraries(CudaOnlySeparateCompilation PRIVATE CUDASeparateLibB)
+target_link_libraries(CudaOnlySeparateCompilation PRIVATE CUDASeparateLibB CUDASeparateLibC)
set_target_properties(CudaOnlySeparateCompilation PROPERTIES
CUDA_STANDARD 11
CUDA_STANDARD_REQUIRED TRUE
diff --git a/Tests/CudaOnly/SeparateCompilation/main/main.cu b/Tests/CudaOnly/SeparateCompilation/main/main.cu
index 2b6e8f4..c3f7ce7 100644
--- a/Tests/CudaOnly/SeparateCompilation/main/main.cu
+++ b/Tests/CudaOnly/SeparateCompilation/main/main.cu
@@ -4,8 +4,8 @@
#include "../file1.h"
#include "../file2.h"
-int file4_launch_kernel(int x);
-int file5_launch_kernel(int x);
+IMPORT int file4_launch_kernel(int x);
+IMPORT int file5_launch_kernel(int x);
int choose_cuda_device()
{
diff --git a/Tests/CudaOnly/SeparateCompilationPTX/main.cu b/Tests/CudaOnly/SeparateCompilationPTX/main.cu
index 164cde5..f94beff 100644
--- a/Tests/CudaOnly/SeparateCompilationPTX/main.cu
+++ b/Tests/CudaOnly/SeparateCompilationPTX/main.cu
@@ -21,10 +21,11 @@ int main()
cuCtxCreate(&context, 0, device);
CUmodule module;
- cuModuleLoadData(&module, kernels);
- if (module == nullptr) {
- std::cerr << "Failed to load the embedded ptx" << std::endl;
+ CUresult result = cuModuleLoadData(&module, kernels);
+ std::cout << "module pointer: " << module << '\n';
+ if (result != CUDA_SUCCESS || module == nullptr) {
+ std::cerr << "Failed to load the embedded ptx with error: "
+ << static_cast<unsigned int>(result) << '\n';
return 1;
}
- std::cout << module << std::endl;
}
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
index 03fba22..0b01085 100644
--- a/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -16,16 +16,18 @@ target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::npp
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)
+# Verify the CUDA Toolkit has static libraries
+if(TARGET CUDA::curand_static AND
+ TARGET CUDA::nppif_static)
#shared runtime with static toolkit libraries
add_library(StaticToolkit SHARED static.cu)
+ target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION")
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
+ #shared runtime with mixed toolkit libraries
add_library(MixedToolkit SHARED mixed.cu)
+ target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION")
target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Shared)
endif()
diff --git a/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
index 2a4da22..d958c3a 100644
--- a/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
+++ b/Tests/CudaOnly/SharedRuntimePlusToolkit/main.cu
@@ -1,19 +1,28 @@
#ifdef _WIN32
# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
IMPORT int shared_version();
+
+#ifdef HAS_STATIC_VERSION
+IMPORT int static_version();
+#else
int static_version()
{
return 0;
}
+#endif
+
+#ifdef HAS_MIXED_VERSION
+IMPORT int mixed_version();
+#else
int mixed_version()
{
return 0;
}
-#else
-int shared_version();
-int static_version();
-int mixed_version();
#endif
int main()
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
index 534bab2..ae03b66 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -16,17 +16,25 @@ 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)
+# Verify the CUDA Toolkit has static libraries
+if(TARGET CUDA::curand_static AND
+ TARGET CUDA::nppif_static)
+ #static runtime with static toolkit libraries
+ add_library(StaticToolkit SHARED static.cu)
+ target_compile_definitions(StaticToolkit INTERFACE "HAS_STATIC_VERSION")
+ 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)
+ #static runtime with mixed toolkit libraries
+ add_library(MixedToolkit SHARED mixed.cu)
+ target_compile_definitions(MixedToolkit INTERFACE "HAS_MIXED_VERSION")
+ target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+ set_target_properties(MixedToolkit PROPERTIES CUDA_RUNTIME_LIBRARY Static)
+endif()
add_executable(CudaOnlyStaticRuntimePlusToolkit main.cu)
-target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
+target_link_libraries(CudaOnlyStaticRuntimePlusToolkit PRIVATE SharedToolkit
+ $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+ $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
if(UNIX)
# Help the shared cuda runtime find libcurand and libnppif when they are not located
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
index 95872f0..fdd7b53 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/curand.cu
@@ -1,6 +1,12 @@
// 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.
@@ -25,7 +31,7 @@
} \
} while (0)
-int curand_main()
+EXPORT int curand_main()
{
size_t n = 100;
size_t i;
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
index 5a09f8e..d958c3a 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/main.cu
@@ -1,8 +1,29 @@
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
-int shared_version();
-int static_version();
-int mixed_version();
+IMPORT int shared_version();
+
+#ifdef HAS_STATIC_VERSION
+IMPORT int static_version();
+#else
+int static_version()
+{
+ return 0;
+}
+#endif
+
+#ifdef HAS_MIXED_VERSION
+IMPORT int mixed_version();
+#else
+int mixed_version()
+{
+ return 0;
+}
+#endif
int main()
{
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
index a05140d..6de6886 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/mixed.cu
@@ -1,8 +1,16 @@
-int curand_main();
-int nppif_main();
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
-int mixed_version()
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int mixed_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
index 2871090..ac5341c 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/nppif.cu
@@ -1,6 +1,12 @@
// 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>
@@ -8,7 +14,7 @@
#include <cuda_runtime_api.h>
#include <nppi_filtering_functions.h>
-int nppif_main()
+EXPORT int nppif_main()
{
/**
* 8-bit unsigned single-channel 1D row convolution.
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
index 9967b66..f3c3dbc 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/shared.cu
@@ -1,8 +1,16 @@
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
+
int curand_main();
int nppif_main();
-int shared_version()
+EXPORT int shared_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
index ca7eb4c..6932fa3 100644
--- a/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
+++ b/Tests/CudaOnly/StaticRuntimePlusToolkit/static.cu
@@ -1,8 +1,16 @@
-int curand_main();
-int nppif_main();
+#ifdef _WIN32
+# define IMPORT __declspec(dllimport)
+# define EXPORT __declspec(dllexport)
+#else
+# define IMPORT
+# define EXPORT
+#endif
-int static_version()
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int static_version()
{
return curand_main() == 0 && nppif_main() == 0;
}
diff --git a/Tests/CudaOnly/Toolkit/CMakeLists.txt b/Tests/CudaOnly/Toolkit/CMakeLists.txt
index 1486c1a..e0801a3 100644
--- a/Tests/CudaOnly/Toolkit/CMakeLists.txt
+++ b/Tests/CudaOnly/Toolkit/CMakeLists.txt
@@ -20,14 +20,20 @@ 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_GREATER 11)
+ list(APPEND cuda_libs nvJitLink)
+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")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -41,6 +47,8 @@ endif()
foreach (cuda_lib )
if(NOT CUDA_${cuda_lib}_LIBRARY)
message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
@@ -50,6 +58,8 @@ 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")
+ elseif(CUDA_${cuda_lib}_LIBRARY MATCHES [[\.\./]])
+ message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY[\"${CUDA_${cuda_lib}_LIBRARY}\"] to not contain /..")
endif()
if(NOT TARGET CUDA::${cuda_lib})
diff --git a/Tests/CustomCommandByproducts/CMakeLists.txt b/Tests/CustomCommandByproducts/CMakeLists.txt
index 08c897c..e391a6f 100644
--- a/Tests/CustomCommandByproducts/CMakeLists.txt
+++ b/Tests/CustomCommandByproducts/CMakeLists.txt
@@ -149,6 +149,29 @@ set_property(TARGET ExternalLibraryWithSubstitution PROPERTY IMPORTED_LOCATION
${binary_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX})
add_dependencies(ExternalLibraryWithSubstitution ExtTargetSubst)
+# Generate the library file of an imported target as an install byproduct
+# of an external project. The byproduct uses <INSTALL_DIR> that is substituted
+# by the real install path
+if(_isMultiConfig)
+ set(cfg /${CMAKE_CFG_INTDIR})
+else()
+ set(cfg)
+endif()
+include(ExternalProject)
+ExternalProject_Add(ExtTargetInstallSubst
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External"
+ DOWNLOAD_COMMAND ""
+ INSTALL_COMMAND
+ "${CMAKE_COMMAND}" -E copy_directory "<BINARY_DIR>${cfg}" "<INSTALL_DIR>${cfg}"
+ BUILD_BYPRODUCTS "<BINARY_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ INSTALL_BYPRODUCTS "<INSTALL_DIR>${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ )
+ExternalProject_Get_Property(ExtTargetInstallSubst install_dir)
+add_library(ExternalLibraryWithInstallDirSubstitution STATIC IMPORTED)
+set_property(TARGET ExternalLibraryWithInstallDirSubstitution PROPERTY IMPORTED_LOCATION
+ ${install_dir}${cfg}/${CMAKE_STATIC_LIBRARY_PREFIX}ExternalLibrary${CMAKE_STATIC_LIBRARY_SUFFIX})
+add_dependencies(ExternalLibraryWithInstallDirSubstitution ExtTargetInstallSubst)
+
# Add an executable consuming all the byproducts.
add_executable(CustomCommandByproducts
CustomCommandByproducts.c
@@ -169,6 +192,18 @@ add_dependencies(CustomCommandByproducts Producer2)
target_link_libraries(CustomCommandByproducts ExternalLibrary)
+add_executable(ExternalLibraryByproducts ExternalLibraryByproducts.c)
+target_link_libraries(ExternalLibraryByproducts ExternalLibrary)
+
+add_executable(ExternalLibraryByproducts_WithSubstitution ExternalLibraryByproducts.c)
+target_link_libraries(ExternalLibraryByproducts_WithSubstitution ExternalLibraryWithSubstitution)
+
+add_executable(ExternalLibraryByproducts_WithInstallDirSubstitution ExternalLibraryByproducts.c)
+target_link_libraries(
+ ExternalLibraryByproducts_WithInstallDirSubstitution
+ ExternalLibraryWithInstallDirSubstitution
+)
+
if(CMAKE_GENERATOR STREQUAL "Ninja")
add_custom_target(CheckNinja ALL
COMMENT "Checking build.ninja"
diff --git a/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c
new file mode 100644
index 0000000..3588e53
--- /dev/null
+++ b/Tests/CustomCommandByproducts/ExternalLibraryByproducts.c
@@ -0,0 +1,5 @@
+extern int ExternalLibrary(void);
+int main(void)
+{
+ return (ExternalLibrary() + 1);
+}
diff --git a/Tests/FindImageMagick/CMakeLists.txt b/Tests/FindImageMagick/CMakeLists.txt
new file mode 100644
index 0000000..8a3c70c
--- /dev/null
+++ b/Tests/FindImageMagick/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindImageMagick.Test COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindImageMagick/Test"
+ "${CMake_BINARY_DIR}/Tests/FindImageMagick/Test"
+ ${build_generator_args}
+ --build-project TestFindImageMagick
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
diff --git a/Tests/FindImageMagick/Test/CMakeLists.txt b/Tests/FindImageMagick/Test/CMakeLists.txt
new file mode 100644
index 0000000..6182260
--- /dev/null
+++ b/Tests/FindImageMagick/Test/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.4)
+project(FindImageMagick C CXX)
+include(CTest)
+
+find_package(ImageMagick REQUIRED COMPONENTS Magick++ MagickWand)
+
+add_executable(test_magick++ main_magick++.cxx)
+target_link_libraries(test_magick++ PRIVATE ImageMagick::Magick++)
+add_test(NAME test_magick++ COMMAND test_magick++)
+
+add_executable(test_magick_wand main_magick_wand.c)
+target_link_libraries(test_magick_wand ImageMagick::MagickWand)
+add_test(NAME test_magick_wand COMMAND test_magick_wand)
diff --git a/Tests/FindImageMagick/Test/main_magick++.cxx b/Tests/FindImageMagick/Test/main_magick++.cxx
new file mode 100644
index 0000000..d0208d4
--- /dev/null
+++ b/Tests/FindImageMagick/Test/main_magick++.cxx
@@ -0,0 +1,10 @@
+#include <iostream>
+#include <string>
+
+#include <Magick++.h>
+
+int main()
+{
+ Magick::InitializeMagick("");
+ return 0;
+}
diff --git a/Tests/FindImageMagick/Test/main_magick_wand.c b/Tests/FindImageMagick/Test/main_magick_wand.c
new file mode 100644
index 0000000..fa6d170
--- /dev/null
+++ b/Tests/FindImageMagick/Test/main_magick_wand.c
@@ -0,0 +1,8 @@
+#include <wand/MagickWand.h>
+
+int main()
+{
+ MagickWand* wand = NewMagickWand();
+ wand = DestroyMagickWand(wand);
+ return 0;
+}
diff --git a/Tests/FindOpenACC/CXXTest/main.cxx b/Tests/FindOpenACC/CXXTest/main.cxx
index 7369045..14b912b 100644
--- a/Tests/FindOpenACC/CXXTest/main.cxx
+++ b/Tests/FindOpenACC/CXXTest/main.cxx
@@ -8,7 +8,7 @@ void vecaddgpu(float* r, float* a, float* b, std::size_t n)
r[i] = a[i] + b[i];
}
-int main(int, char* [])
+int main(int, char*[])
{
const std::size_t n = 100000; /* vector length */
std::vector<float> a(n); /* input vector 1 */
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index d4cf36b..b6942c9 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -377,6 +377,7 @@ if(CMake_TEST_FindPython)
--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_SABIModule=${CMake_TEST_FindPython_SABIModule}"
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
@@ -478,6 +479,35 @@ if(CMake_TEST_FindPython)
endif()
endif()
+if(CMake_TEST_FindPython_SABIModule)
+ add_test(NAME FindPython.Python2.Development.SABIModule COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python2SABIModule"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python2SABIModule"
+ ${build_generator_args}
+ --build-project TestPython2SABIModule
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ set_tests_properties(FindPython.Python2.Development.SABIModule PROPERTIES
+ PASS_REGULAR_EXPRESSION "Could NOT find Python2 \\(missing: .*Development\\.SABIModule")
+
+ # Use exclusively Release configuration because Debug is, on Windows with MSVC,
+ # unusable with SABI: Python force link with debug version of full versioned library rather than
+ # the stable ABI one.
+ add_test(NAME FindPython.Python3.Development.SABIModule COMMAND
+ ${CMAKE_CTEST_COMMAND} -C Release
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/Python3SABIModule"
+ "${CMake_BINARY_DIR}/Tests/FindPython/Python3SABIModule"
+ ${build_generator_args}
+ --build-project TestPython3SABIModule
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C Release
+ )
+endif()
+
if(CMake_TEST_FindPython_NumPy)
add_test(NAME FindPython.NumPy COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
diff --git a/Tests/FindPython/Python2SABIModule/CMakeLists.txt b/Tests/FindPython/Python2SABIModule/CMakeLists.txt
new file mode 100644
index 0000000..4f01197
--- /dev/null
+++ b/Tests/FindPython/Python2SABIModule/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython2SABIModule LANGUAGES C)
+
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development.Module Development.SABIModule)
diff --git a/Tests/FindPython/Python3Module/CMakeLists.txt b/Tests/FindPython/Python3Module/CMakeLists.txt
index 5945962..ccc1fdb 100644
--- a/Tests/FindPython/Python3Module/CMakeLists.txt
+++ b/Tests/FindPython/Python3Module/CMakeLists.txt
@@ -11,6 +11,9 @@ endif()
if (Python3_Development_FOUND)
message (FATAL_ERROR "Python 3, COMPONENT 'Development' unexpectedly found")
endif()
+if (Python3_Development.SABIModule_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.SABIModule' unexpectedly found")
+endif()
if (Python3_Development.Embed_FOUND)
message (FATAL_ERROR "Python 3, COMPONENT 'Development.Embed' unexpectedly found")
endif()
@@ -25,6 +28,12 @@ endif()
if(TARGET Python3::Python)
message(SEND_ERROR "Python3::Python unexpectedly found")
endif()
+if(TARGET Python3::SABIMOdule)
+ message(SEND_ERROR "Python3::SABIModule unexpectedly found")
+endif()
+if(TARGET Python3::Embed)
+ message(SEND_ERROR "Python3::Embed unexpectedly found")
+endif()
if(NOT TARGET Python3::Module)
message(SEND_ERROR "Python3::Module not found")
endif()
diff --git a/Tests/FindPython/Python3SABIModule/CMakeLists.txt b/Tests/FindPython/Python3SABIModule/CMakeLists.txt
new file mode 100644
index 0000000..2a067d0
--- /dev/null
+++ b/Tests/FindPython/Python3SABIModule/CMakeLists.txt
@@ -0,0 +1,51 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestPython3SABIModule LANGUAGES C)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development.SABIModule)
+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 (Python3_Development.Module_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.Module' unexpectedly found")
+endif()
+if (NOT Python3_Development.SABIModule_FOUND)
+ message (FATAL_ERROR "Python 3, COMPONENT 'Development.SABIModule' 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(TARGET Python3::Module)
+ message(SEND_ERROR "Python3::Module unexpectedly found")
+endif()
+if(NOT TARGET Python3::SABIModule)
+ message(SEND_ERROR "Python3::SABIModule not found")
+endif()
+
+Python3_add_library (spam3 MODULE USE_SABI 3 WITH_SOABI ../spam.c)
+target_compile_definitions (spam3 PRIVATE PYTHON3)
+
+if (Python3_SOSABI)
+ get_property (suffix TARGET spam3 PROPERTY SUFFIX)
+ if (NOT suffix MATCHES "^.${Python3_SOSABI}")
+ message(FATAL_ERROR "Module suffix do not include Python3_SOSABI")
+ endif()
+endif()
+
+
+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
index ae50f32..42d282d 100644
--- a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
+++ b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
@@ -8,7 +8,12 @@ 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)
+
+set(components Interpreter Development)
+if (CMake_TEST_FindPython_SABIModule AND WIN32)
+ list (APPEND components Development.SABIModule)
+endif()
+find_package(Python3 REQUIRED COMPONENTS ${components})
if (NOT Python3_FOUND)
message (FATAL_ERROR "Failed to find Python 3")
endif()
@@ -108,3 +113,28 @@ add_test(NAME FindPython.RequiredArtifacts.Library-Include.INVALID COMMAND
"-DPython3_INCLUDE_DIR=${Python2_INCLUDE_DIRS}"
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+
+if (CMake_TEST_FindPython_SABIModule AND WIN32)
+ add_test(NAME FindPython.RequiredArtifacts.SABILibrary.VALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/SABILibrary.VALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=TRUE -DCHECK_SABI_LIBRARY=ON
+ "-DPython3_SABI_LIBRARY=${Python3_SABI_LIBRARY_RELEASE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+ add_test(NAME FindPython.RequiredArtifacts.SABILibrary.INVALID COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/RequiredArtifacts/Check"
+ "${CMake_BINARY_DIR}/Tests/FindPython/RequiredArtifacts/SABILibrary.INVALID"
+ ${build_generator_args}
+ --build-project TestRequiredArtifacts.Check
+ --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_SABI_LIBRARY=ON
+ "-DPython3_SABI_LIBRARY=${Python2_LIBRARY_RELEASE}"
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
+endif()
diff --git a/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt
index 287cfdb..bb4f67c 100644
--- a/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt
+++ b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt
@@ -16,6 +16,10 @@ if (CHECK_LIBRARY OR CHECK_INCLUDE)
set (required_include "${Python3_INCLUDE_DIR}")
endif()
endif()
+if (CHECK_SABI_LIBRARY)
+ list (APPEND components Development.SABIModule)
+ set (required_sabi_library "${Python3_SABI_LIBRARY}")
+endif()
find_package (Python3 COMPONENTS ${components})
@@ -39,3 +43,7 @@ endif()
if (CHECK_INCLUDE AND NOT Python3_INCLUDE_DIRS STREQUAL required_include)
message (FATAL_ERROR "Failed to use input variable Python3_INCLUDE_DIR")
endif()
+
+if (CHECK_SABI_LIBRARY AND NOT Python3_SABI_LIBRARY_RELEASE STREQUAL required_sabi_library)
+ message (FATAL_ERROR "Failed to use input variable Python3_SABI_LIBRARY")
+endif()
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
index b07c214..fc71a18 100644
--- a/Tests/FortranOnly/CMakeLists.txt
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -56,8 +56,6 @@ add_custom_target(checksayhello ALL
)
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([[
@@ -66,10 +64,24 @@ CHECK_Fortran_SOURCE_COMPILES([[
END
]] HAVE_PRINT)
if(NOT HAVE_PRINT)
- if(EXISTS "${err_log}")
- file(READ "${err_log}" err)
+ set(configure_log "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml")
+ if(EXISTS "${configure_log}")
+ file(READ "${configure_log}" log_content)
+ else()
+ set(log_content "")
+ endif()
+ if(log_content MATCHES [[( -
+ kind: "try_compile-v1"(
++ [^
+]+)+
+ checks:
+ - "Performing Test HAVE_PRINT"(
++ [^
+]+)+)]])
+ set(err "${CMAKE_MATCH_1}")
+ else()
+ set(err "")
endif()
- string(REPLACE "\n" "\n " err " ${err}")
message(SEND_ERROR "CHECK_Fortran_SOURCE_COMPILES for HAVE_PRINT failed:\n"
"${err}")
endif()
diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index ebbe288..3fb53d1 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -200,6 +200,12 @@ 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_library(importedFallback_genex STATIC IMPORTED)
+set_property(TARGET importedFallback_genex PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+set_property(TARGET importedFallback_genex PROPERTY IMPORTED_LOCATION_RELEASE release_loc)
+set_property(TARGET importedFallback_genex PROPERTY
+ INTERFACE_COMPILE_DEFINITIONS $<$<CONFIG:Release>:FOOBAR=1>)
+
add_custom_target(check-part3 ALL
COMMAND ${msys2_no_conv} ${CMAKE_COMMAND}
-Dtest_version_greater_1=$<VERSION_GREATER:1.0,1.1.1>
@@ -211,6 +217,7 @@ add_custom_target(check-part3 ALL
-Dconfig=$<CONFIGURATION>
-Dtest_imported_includes=$<TARGET_PROPERTY:imported4,INCLUDE_DIRECTORIES>
-Dtest_imported_fallback=$<STREQUAL:$<TARGET_FILE_NAME:importedFallback>,fallback_loc>
+ -Dtest_imported_fallback_genex=$<STREQUAL:$<TARGET_PROPERTY:importedFallback_genex,INTERFACE_COMPILE_DEFINITIONS>,FOOBAR=1>
-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>>
@@ -261,13 +268,24 @@ else()
set(test_shell_path2 /shell/path /another/path)
endif()
+set(test_shell_path_genex "$<SHELL_PATH:${test_shell_path}>")
+set(test_shell_path2_genex "$<SHELL_PATH:${test_shell_path2}>")
+if(msys1_prefix)
+ # Add a prefix to the value produced by the genex so that the path does
+ # not look absolute, thus suppressing conversion by MSYS 1.0 bash.
+ set(test_shell_path_genex "${msys1_prefix}${test_shell_path_genex}")
+ # There is no way to suppress conversion of the second path in
+ # MSYS 1.0 bash, so do the comparison at generate time instead.
+ set(test_shell_path2_genex "$<STREQUAL:${test_shell_path2_genex},/c/shell/path:/d/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}>"
+ "-Dtest_shell_path=${test_shell_path_genex}"
+ "-Dtest_shell_path2=${test_shell_path2_genex}"
-Dif_1=$<IF:1,a,b>
-Dif_2=$<IF:0,a,b>
-Dif_3=$<IF:$<EQUAL:10,30>,a,b>
diff --git a/Tests/GeneratorExpression/check-part3.cmake b/Tests/GeneratorExpression/check-part3.cmake
index 5571c3d..e1b1f93 100644
--- a/Tests/GeneratorExpression/check-part3.cmake
+++ b/Tests/GeneratorExpression/check-part3.cmake
@@ -19,6 +19,7 @@ else()
endif()
check(test_imported_fallback "1")
+check(test_imported_fallback_genex "1")
check(test_alias_file_exe "1")
check(test_alias_file_lib "1")
diff --git a/Tests/GeneratorExpression/check-part4.cmake b/Tests/GeneratorExpression/check-part4.cmake
index a7e0944..28f3699 100644
--- a/Tests/GeneratorExpression/check-part4.cmake
+++ b/Tests/GeneratorExpression/check-part4.cmake
@@ -16,8 +16,13 @@ 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]])
+ if(CMAKE_GENERATOR STREQUAL "MSYS Makefiles")
+ if(msys1_prefix)
+ # The comparison was done at generate time with the STREQUAL genex.
+ check(test_shell_path2 [[1]])
+ else()
+ check(test_shell_path2 [[/c/shell/path:/d/another/path]])
+ endif()
elseif(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
check(test_shell_path2 [[c:/shell/path;d:/another/path]])
else()
diff --git a/Tests/PositionIndependentTargets/.gitattributes b/Tests/PositionIndependentTargets/.gitattributes
index 61b2751..ed36631 100644
--- a/Tests/PositionIndependentTargets/.gitattributes
+++ b/Tests/PositionIndependentTargets/.gitattributes
@@ -1,2 +1,2 @@
# Do not format a source where we want a long line preserved.
-pic_test.h -format.clang-format-6.0
+pic_test.h -format.clang-format
diff --git a/Tests/QtAutogen/Complex/calwidget.cpp b/Tests/QtAutogen/Complex/calwidget.cpp
index f58b182..202ed49 100644
--- a/Tests/QtAutogen/Complex/calwidget.cpp
+++ b/Tests/QtAutogen/Complex/calwidget.cpp
@@ -433,4 +433,4 @@ QComboBox* Window::createColorComboBox()
return comboBox;
}
-//#include "moc_calwidget.cpp"
+// #include "moc_calwidget.cpp"
diff --git a/Tests/RunCMake/AutoExportDll/AutoExport.cmake b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
index fe57d56..024c647 100644
--- a/Tests/RunCMake/AutoExportDll/AutoExport.cmake
+++ b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
@@ -7,7 +7,7 @@ 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
- AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
+ AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
set_property(TARGET autoexport3 PROPERTY COMMON_LANGUAGE_RUNTIME "")
endif()
@@ -17,7 +17,7 @@ if(MSVC)
add_library(autoexport_for_exec SHARED hello2.c)
target_link_libraries(autoexport_for_exec say)
if(NOT MSVC_VERSION VERSION_LESS 1600 AND
- NOT CMAKE_VS_PLATFORM_NAME STREQUAL "ARM64")
+ NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
enable_language(ASM_MASM)
target_sources(autoexport PRIVATE nop.asm)
set_property(SOURCE nop.asm PROPERTY COMPILE_FLAGS /safeseh)
diff --git a/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt
new file mode 100644
index 0000000..66d3016
--- /dev/null
+++ b/Tests/RunCMake/CMP0104/CMP0104-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0104-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0104 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt
new file mode 100644
index 0000000..ef48d5c
--- /dev/null
+++ b/Tests/RunCMake/CMP0106/CMP0106-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0106-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0106 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 3038ed8..930122c 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -200,6 +200,9 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
if(WIN32)
add_executable(showIncludes showIncludes.c)
list(APPEND Ninja_ARGS -DshowIncludes=$<TARGET_FILE:showIncludes>)
+ if(CMake_TEST_NO_CODEPAGE_9xx)
+ list(APPEND Ninja_ARGS -DCMake_TEST_NO_CODEPAGE_9xx=1)
+ endif()
endif()
add_RunCMake_test(Ninja)
set(NinjaMultiConfig_ARGS
@@ -299,8 +302,8 @@ if(UNIX AND "${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
add_RunCMake_test(CompilerChange)
endif()
add_RunCMake_test(CompilerNotFound)
-if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
- list(APPEND CompilerTest_ARGS -DCMake_TEST_OBJC=1)
+if(DEFINED CMake_TEST_OBJC)
+ list(APPEND CompilerTest_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
endif()
if(CMAKE_Fortran_COMPILER)
list(APPEND CompilerTest_ARGS -DCMake_TEST_Fortran=1)
@@ -351,6 +354,7 @@ add_RunCMake_test(GenEx-LINK_LIBRARY)
add_RunCMake_test(GenEx-LINK_GROUP)
add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
add_RunCMake_test(GenEx-GENEX_EVAL)
+add_RunCMake_test(GenEx-TARGET_PROPERTY)
add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
add_RunCMake_test(GenEx-PATH)
add_RunCMake_test(GenEx-PATH_EQUAL)
@@ -361,11 +365,10 @@ if(XCODE_VERSION)
set(GeneratorToolset_ARGS -DXCODE_VERSION=${XCODE_VERSION})
endif()
add_RunCMake_test(GeneratorToolset)
-add_RunCMake_test(GetPrerequisites)
+add_RunCMake_test(GetPrerequisites -DSAMPLE_EXE=$<TARGET_FILE:exit_code>)
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(LinkItemValidation)
add_RunCMake_test(LinkStatic)
@@ -466,6 +469,15 @@ add_RunCMake_test(ctest_fixtures)
add_RunCMake_test(define_property)
add_RunCMake_test(file -DCYGWIN=${CYGWIN} -DMSYS=${MSYS})
add_RunCMake_test(file-CHMOD -DMSYS=${MSYS})
+foreach(var
+ CMake_TEST_NO_NETWORK
+ CMake_TEST_TLS_VERIFY_URL
+ )
+ if(DEFINED ${var})
+ list(APPEND file-DOWNLOAD_ARGS -D${var}=${${var}})
+ endif()
+endforeach()
+add_RunCMake_test(file-DOWNLOAD)
add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
add_RunCMake_test(find_file)
add_RunCMake_test(find_library -DCYGWIN=${CYGWIN} -DMSYS=${MSYS})
@@ -502,64 +514,15 @@ if(APPLE)
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()
- if(CMAKE_VERSION VERSION_LESS 3.20.6 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xIntelLLVM" AND "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
- # Older CMake versions accidentally set the default standards to empty when
- # IntelLLVM targets the MSVC ABI, thus not activating standard selection.
- # Approximate the logic from IntelLLVM-{C,CXX}.cmake.
- if(DEFINED CMAKE_C_STANDARD_DEFAULT AND "${CMAKE_C_STANDARD_DEFAULT}" STREQUAL "")
- set(CMAKE_C_STANDARD_DEFAULT 17)
- endif()
- if(DEFINED CMAKE_CXX_STANDARD_DEFAULT AND "${CMAKE_CXX_STANDARD_DEFAULT}" STREQUAL "")
- set(CMAKE_CXX_STANDARD_DEFAULT 14)
- endif()
- endif()
foreach(
var
IN ITEMS
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_HIP
+ CMake_TEST_OBJC
CMake_TEST_FILESYSTEM_1S
- CMAKE_OBJC_STANDARD_DEFAULT
- CMAKE_OBJCXX_STANDARD_DEFAULT
)
if(DEFINED ${var})
list(APPEND try_compile_ARGS -D${var}=${${var}})
@@ -684,7 +647,8 @@ if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
endif()
if(XCODE_VERSION)
- add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION})
+ add_RunCMake_test(XcodeProject -DXCODE_VERSION=${XCODE_VERSION}
+ -DCMake_TEST_Swift=${CMake_TEST_Swift})
add_RunCMake_test(XcodeProject-Embed -DXCODE_VERSION=${XCODE_VERSION})
# This test can take a very long time due to lots of combinations.
@@ -741,6 +705,7 @@ add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_I
set_property(TEST RunCMake.target_link_options APPEND
PROPERTY LABELS "CUDA")
+add_RunCMake_test(add_compile_definitions)
add_RunCMake_test(target_compile_definitions)
add_RunCMake_test(target_compile_features)
add_RunCMake_test(target_compile_options
@@ -752,11 +717,13 @@ 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}
- -DCMake_TEST_HIP=${CMake_TEST_HIP})
+ -DCMake_TEST_HIP=${CMake_TEST_HIP}
+ -DCMake_TEST_Swift=${CMake_TEST_Swift})
add_RunCMake_test(CheckSourceCompiles -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
-DCMake_TEST_ISPC=${CMake_TEST_ISPC}
-DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
- -DCMake_TEST_HIP=${CMake_TEST_HIP})
+ -DCMake_TEST_HIP=${CMake_TEST_HIP}
+ -DCMake_TEST_Swift=${CMake_TEST_Swift})
add_RunCMake_test(CheckSourceRuns -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
-DCMAKE_Fortran_COMPILER_ID=${CMAKE_Fortran_COMPILER_ID}
-DCMake_TEST_HIP=${CMake_TEST_HIP})
@@ -806,8 +773,11 @@ add_RunCMake_test(install -DNO_NAMELINK=${NO_NAMELINK} -DCYGWIN=${CYGWIN} -DMSYS
set_property(TEST RunCMake.install APPEND
PROPERTY LABELS "ISPC")
+if(DEFINED CMake_COMPILER_FORCES_NEW_DTAGS)
+ list(APPEND file-GET_RUNTIME_DEPENDENCIES_ARGS
+ -DCMake_COMPILER_FORCES_NEW_DTAGS=${CMake_COMPILER_FORCES_NEW_DTAGS})
+endif()
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}
)
@@ -896,13 +866,13 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
if(DEFINED CMake_TEST_ISPC)
list(APPEND CompilerLauncher_ARGS -DCMake_TEST_ISPC=${CMake_TEST_ISPC})
endif()
+ if(DEFINED CMake_TEST_OBJC)
+ list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
+ list(APPEND LinkerLauncher_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
+ 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)
- list(APPEND LinkerLauncher_ARGS -DCMake_TEST_OBJC=1)
- endif()
add_RunCMake_test(CompilerLauncher)
set_property(TEST RunCMake.CompilerLauncher APPEND
PROPERTY LABELS "CUDA;HIP;ISPC")
diff --git a/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt b/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt
index c23ab89..f32056a 100644
--- a/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt
+++ b/Tests/RunCMake/CMakePresets/NoDebug-stdout.txt
@@ -1,2 +1,2 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
index 1c7b836..5bd0158 100644
--- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
@@ -1,5 +1,9 @@
include(RunCMake)
+# Isolate our ctest runs from external environment.
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+
# Presets do not support legacy VS generator name architecture suffix.
if(RunCMake_GENERATOR MATCHES "^(Visual Studio [0-9]+ [0-9]+) ")
set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
diff --git a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt
index 55bb894..da548a6 100644
--- a/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt
+++ b/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-stdout.txt
@@ -1,2 +1 @@
-- Configuring incomplete, errors occurred!
-See also ".*/Tests/RunCMake/CTestCommandExpandLists/multipleExpandOptions-build/CMakeFiles/CMakeOutput\.log".
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index df3e82a..bda260a 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -3,9 +3,6 @@ include(RunCTest)
set(RunCMake_TEST_TIMEOUT 60)
-unset(ENV{CTEST_PARALLEL_LEVEL})
-unset(ENV{CTEST_OUTPUT_ON_FAILURE})
-
run_cmake_command(repeat-opt-bad1
${CMAKE_CTEST_COMMAND} --repeat until-pass
)
@@ -392,6 +389,14 @@ function(run_NoTests)
run_cmake_command(no-tests_error ${CMAKE_CTEST_COMMAND} --no-tests=error)
run_cmake_command(no-tests_bad ${CMAKE_CTEST_COMMAND} --no-tests=bad)
run_cmake_command(no-tests_legacy ${CMAKE_CTEST_COMMAND})
+
+ run_cmake_command(no-tests_env_ignore ${CMAKE_COMMAND} -E env CTEST_NO_TESTS_ACTION=ignore ${CMAKE_CTEST_COMMAND})
+ run_cmake_command(no-tests_env_error ${CMAKE_COMMAND} -E env CTEST_NO_TESTS_ACTION=error ${CMAKE_CTEST_COMMAND})
+ run_cmake_command(no-tests_env_bad ${CMAKE_COMMAND} -E env CTEST_NO_TESTS_ACTION=bad ${CMAKE_CTEST_COMMAND})
+ run_cmake_command(no-tests_env_empty_legacy ${CMAKE_COMMAND} -E env CTEST_NO_TESTS_ACTION= ${CMAKE_CTEST_COMMAND})
+
+ run_cmake_command(no-tests_env_bad_with_cli_error ${CMAKE_COMMAND} -E env CTEST_NO_TESTS_ACTION=bad ${CMAKE_CTEST_COMMAND} --no-tests=error)
+
file(WRITE "${RunCMake_TEST_BINARY_DIR}/NoTestsScript.cmake" "
set(CTEST_COMMAND \"${CMAKE_CTEST_COMMAND}\")
set(CTEST_SOURCE_DIRECTORY \"${RunCMake_SOURCE_DIR}\")
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-result.txt
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad-result.txt
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_bad-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad-stderr.txt
new file mode 100644
index 0000000..97187e6
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad-stderr.txt
@@ -0,0 +1 @@
+^Unknown value for CTEST_NO_TESTS_ACTION: 'bad'$
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-result.txt
new file mode 100644
index 0000000..45a4fb7
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-result.txt
@@ -0,0 +1 @@
+8
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-stderr.txt
new file mode 100644
index 0000000..eafba1c
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_bad_with_cli_error-stderr.txt
@@ -0,0 +1 @@
+No tests were found!!!
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_empty_legacy-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_empty_legacy-stderr.txt
new file mode 100644
index 0000000..a7c4b11
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_empty_legacy-stderr.txt
@@ -0,0 +1 @@
+^No tests were found!!!$
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_error-result.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_error-result.txt
new file mode 100644
index 0000000..45a4fb7
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_error-result.txt
@@ -0,0 +1 @@
+8
diff --git a/Tests/RunCMake/CTestCommandLine/no-tests_env_error-stderr.txt b/Tests/RunCMake/CTestCommandLine/no-tests_env_error-stderr.txt
new file mode 100644
index 0000000..eafba1c
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/no-tests_env_error-stderr.txt
@@ -0,0 +1 @@
+No tests were found!!!
diff --git a/Tests/RunCMake/CXXModules/CMakeLists.txt b/Tests/RunCMake/CXXModules/CMakeLists.txt
index 708d92c..5246bef 100644
--- a/Tests/RunCMake/CXXModules/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.23)
project(${RunCMake_TEST} NONE)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterfaceImported.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterfaceImported.cmake
index 9ff5606..d287198 100644
--- a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterfaceImported.cmake
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterfaceImported.cmake
@@ -1,4 +1,4 @@
-add_library(module-header SHARED IMPORTED)
+add_library(module-header INTERFACE IMPORTED)
target_sources(module-header
INTERFACE
FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterfaceImported.cmake b/Tests/RunCMake/CXXModules/FileSetModulesInterfaceImported.cmake
index 6640ae9..392149f 100644
--- a/Tests/RunCMake/CXXModules/FileSetModulesInterfaceImported.cmake
+++ b/Tests/RunCMake/CXXModules/FileSetModulesInterfaceImported.cmake
@@ -1,4 +1,4 @@
-add_library(module SHARED IMPORTED)
+add_library(module INTERFACE IMPORTED)
target_sources(module
INTERFACE
FILE_SET fs TYPE CXX_MODULES FILES
diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt
index 8ac0fc5..a0b2572 100644
--- a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt
+++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt
@@ -22,6 +22,11 @@ CMake Error:
by the generator
(
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
+)?(
CMake Error in CMakeLists.txt:
The "nodyndep" target contains C\+\+ module sources which are not supported
by the generator
diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
index 0f32ea0..c1129ca 100644
--- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
@@ -36,10 +36,20 @@ if (RunCMake_GENERATOR MATCHES "Ninja")
endif ()
endif ()
+set(generator_supports_cxx_modules 0)
+if (RunCMake_GENERATOR MATCHES "Ninja" AND
+ ninja_version VERSION_GREATER_EQUAL "1.11" AND
+ "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+ set(generator_supports_cxx_modules 1)
+endif ()
+
+if (RunCMake_GENERATOR MATCHES "Visual Studio" AND
+ CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.34")
+ set(generator_supports_cxx_modules 1)
+endif ()
+
# Test behavior when the generator does not support C++20 modules.
-if (NOT RunCMake_GENERATOR MATCHES "Ninja" OR
- ninja_version VERSION_LESS "1.11" OR
- NOT "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+if (NOT generator_supports_cxx_modules)
if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
run_cmake(NoDyndepSupport)
endif ()
@@ -79,6 +89,8 @@ if (RunCMake_GENERATOR MATCHES "Ninja")
run_cmake(NinjaDependInfoFileSet)
run_cmake(NinjaDependInfoExport)
run_cmake(NinjaDependInfoBMIInstall)
+elseif (RunCMake_GENERATOR MATCHES "Visual Studio")
+ # Not supported yet.
else ()
message(FATAL_ERROR
"Please add 'DependInfo' tests for the '${RunCMake_GENERATOR}' generator.")
@@ -120,7 +132,9 @@ function (run_cxx_module_test directory)
if (RunCMake_CXXModules_INSTALL)
run_cmake_command("examples/${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug)
endif ()
- run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
+ if (NOT RunCMake_CXXModules_NO_TEST)
+ run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
+ endif ()
endfunction ()
string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}")
@@ -130,8 +144,17 @@ if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
run_cxx_module_test(simple)
run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF)
run_cxx_module_test(generated)
- run_cxx_module_test(public-req-private)
run_cxx_module_test(deep-chain)
+ run_cxx_module_test(duplicate)
+ set(RunCMake_CXXModules_NO_TEST 1)
+ run_cxx_module_test(circular)
+ unset(RunCMake_CXXModules_NO_TEST)
+ run_cxx_module_test(scan_properties)
+endif ()
+
+# Tests which require collation work.
+if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
+ run_cxx_module_test(public-req-private)
endif ()
# Tests which use named modules in shared libraries.
@@ -151,6 +174,7 @@ endif ()
# Tests which install BMIs
if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
+ run_cxx_module_test(export-interface-no-properties-build)
run_cxx_module_test(export-interface-build)
run_cxx_module_test(export-bmi-and-interface-build)
endif ()
@@ -164,6 +188,7 @@ if ("install_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
run_cxx_module_test(install-bmi-and-interfaces)
if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
+ run_cxx_module_test(export-interface-no-properties-install)
run_cxx_module_test(export-interface-install)
run_cxx_module_test(export-bmi-and-interface-install)
endif ()
diff --git a/Tests/RunCMake/CXXModules/compiler_introspection.cmake b/Tests/RunCMake/CXXModules/compiler_introspection.cmake
index 7a2df3d..0e61383 100644
--- a/Tests/RunCMake/CXXModules/compiler_introspection.cmake
+++ b/Tests/RunCMake/CXXModules/compiler_introspection.cmake
@@ -20,6 +20,7 @@ string(APPEND info "\
set(CMAKE_CXX_COMPILE_FEATURES \"${CMAKE_CXX_COMPILE_FEATURES}\")
set(CMAKE_MAKE_PROGRAM \"${CMAKE_MAKE_PROGRAM}\")
set(forced_cxx_standard \"${forced_cxx_standard}\")
+set(CMAKE_CXX_COMPILER_VERSION \"${CMAKE_CXX_COMPILER_VERSION}\")
")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-result.txt
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt
new file mode 100644
index 0000000..ac80356
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt
@@ -0,0 +1 @@
+((Ninja generators)?(build stopped: dependency cycle:)|(Visual Studio generators)?(error : Cannot build the following source files because there is a cyclic dependency between them))
diff --git a/Tests/RunCMake/CXXModules/examples/circular-stderr.txt b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+ CMake's C\+\+ module support is experimental. It is meant only for
+ experimentation and feedback to CMake developers.
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt
new file mode 100644
index 0000000..4d1997c
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_circular CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_library(circular STATIC)
+target_sources(circular
+ PUBLIC
+ FILE_SET CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ circular-a.cppm
+ circular-b.cppm)
+target_compile_features(circular PUBLIC cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm
new file mode 100644
index 0000000..eea842b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/circular-a.cppm
@@ -0,0 +1,6 @@
+export module a;
+import b;
+
+export int a() {
+ return b();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm
new file mode 100644
index 0000000..fc6dc42
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular/circular-b.cppm
@@ -0,0 +1,6 @@
+export module b;
+import a;
+
+export int b() {
+ return a();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/cxx-modules-find-bmi.cmake b/Tests/RunCMake/CXXModules/examples/cxx-modules-find-bmi.cmake
index 91f3995..88d50db 100644
--- a/Tests/RunCMake/CXXModules/examples/cxx-modules-find-bmi.cmake
+++ b/Tests/RunCMake/CXXModules/examples/cxx-modules-find-bmi.cmake
@@ -1,6 +1,6 @@
function (check_for_bmi prefix destination name)
set(found 0)
- foreach (ext IN ITEMS gcm ifc)
+ foreach (ext IN ITEMS gcm ifc pcm)
if (EXISTS "${prefix}/${destination}/${name}.${ext}")
set(found 1)
break ()
diff --git a/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake
index 381094e..5f34fc0 100644
--- a/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake
+++ b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake
@@ -1,4 +1,4 @@
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
if (NOT EXISTS "${CMake_TEST_MODULE_COMPILATION_RULES}")
message(FATAL_ERROR
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+ CMake's C\+\+ module support is experimental. It is meant only for
+ experimentation and feedback to CMake developers.
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt
new file mode 100644
index 0000000..27be7a8
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_duplicate CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_executable(duplicate)
+target_sources(duplicate
+ PRIVATE
+ main.cxx
+ PRIVATE
+ FILE_SET CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ duplicate.cxx)
+target_compile_features(duplicate PRIVATE cxx_std_20)
+target_compile_definitions(duplicate PRIVATE NDUPLICATE=1)
+
+add_executable(duplicate2)
+target_sources(duplicate2
+ PRIVATE
+ main.cxx
+ PRIVATE
+ FILE_SET CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ duplicate.cxx)
+target_compile_features(duplicate2 PRIVATE cxx_std_20)
+target_compile_definitions(duplicate2 PRIVATE NDUPLICATE=2)
+
+add_test(NAME duplicate COMMAND duplicate)
+set_property(TEST duplicate
+ PROPERTY
+ PASS_REGULAR_EXPRESSION "From duplicate #1")
+add_test(NAME duplicate2 COMMAND duplicate2)
+set_property(TEST duplicate2
+ PROPERTY
+ PASS_REGULAR_EXPRESSION "From duplicate #2")
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx
new file mode 100644
index 0000000..c0c820b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/duplicate.cxx
@@ -0,0 +1,11 @@
+module;
+
+#include <iostream>
+
+export module duplicate;
+
+export int from_import()
+{
+ std::cerr << "From duplicate #" << NDUPLICATE << std::endl;
+ return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx
new file mode 100644
index 0000000..c2c0636
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/duplicate/main.cxx
@@ -0,0 +1,6 @@
+import duplicate;
+
+int main(int argc, char* argv[])
+{
+ return from_import();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx
index e0b1872..8dfc41b 100644
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx
@@ -1,6 +1,8 @@
export module importable;
+extern "C++" {
int forwarding();
+}
export int from_import()
{
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/test/CMakeLists.txt
index b814b3b..2e37da2 100644
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/test/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/test/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_library NONE)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
find_package(export_bmi_and_interfaces REQUIRED)
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx
index e0b1872..8dfc41b 100644
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx
@@ -1,6 +1,8 @@
export module importable;
+extern "C++" {
int forwarding();
+}
export int from_import()
{
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/test/CMakeLists.txt
index db0484d..1adccb3 100644
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/test/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/test/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_library NONE)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
find_package(export_bmi_and_interfaces REQUIRED)
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt
index 80ddaf8..8584dce 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt
@@ -26,7 +26,8 @@ install(TARGETS export_interfaces
FILE_SET modules DESTINATION "lib/cxx/miu")
export(EXPORT CXXModules
NAMESPACE CXXModules::
- FILE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-targets.cmake")
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-targets.cmake"
+ CXX_MODULES_DIRECTORY "export_interfaces-cxx-modules")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-config.cmake"
"include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces-targets.cmake\")
set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
@@ -46,7 +47,8 @@ endif ()
add_test(NAME export_interfaces_build
COMMAND
"${CMAKE_COMMAND}"
- "-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
+ "-Dexpected_source_dir=${CMAKE_CURRENT_SOURCE_DIR}"
+ "-Dexpected_binary_dir=${CMAKE_CURRENT_BINARY_DIR}"
"-Dexport_interfaces_DIR=${CMAKE_CURRENT_BINARY_DIR}"
${generator}
-S "${CMAKE_CURRENT_SOURCE_DIR}/test"
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-build/importable.cxx
index e0b1872..8dfc41b 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-build/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-build/importable.cxx
@@ -1,6 +1,8 @@
export module importable;
+extern "C++" {
int forwarding();
+}
export int from_import()
{
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt
index 6145210..9949969 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_library NONE)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
find_package(export_interfaces REQUIRED)
@@ -19,14 +19,14 @@ endif ()
get_property(file_set_files TARGET CXXModules::export_interfaces
PROPERTY CXX_MODULE_SET_modules)
-if (NOT file_set_files STREQUAL "${expected_dir}/importable.cxx")
+if (NOT file_set_files STREQUAL "${expected_source_dir}/importable.cxx")
message(FATAL_ERROR
"Incorrect exported file set paths in CXXModules::export_interfaces`: `${file_set_files}`")
endif ()
-get_property(imported_modules_set TARGET CXXModules::export_interfaces
- PROPERTY IMPORTED_CXX_MODULES_DEBUG SET)
-if (imported_modules_set)
+get_property(imported_modules TARGET CXXModules::export_interfaces
+ PROPERTY IMPORTED_CXX_MODULES_DEBUG)
+if (NOT imported_modules MATCHES "importable=${expected_source_dir}/importable.cxx,${expected_binary_dir}/CMakeFiles/export_interfaces.dir(/Debug)?/importable.(gcm|pcm|ifc)")
message(FATAL_ERROR
- "Unexpected C++ modules specified.")
+ "Incorrect exported modules in CXXModules::export_interfaces`: `${imported_modules}`\n`importable=${expected_source_dir}/importable.cxx,${expected_binary_dir}/CMakeFiles/export_interfaces.dir(/Debug)?/importable.(gcm|pcm|ifc)`")
endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt
index 1dfb6da..b5c6224 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt
@@ -27,7 +27,8 @@ install(TARGETS export_interfaces
install(EXPORT CXXModules
NAMESPACE CXXModules::
DESTINATION "lib/cmake/export_interfaces"
- FILE "export_interfaces-targets.cmake")
+ FILE "export_interfaces-targets.cmake"
+ CXX_MODULES_DIRECTORY "export_interfaces-cxx-modules")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-config.cmake"
"include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces-targets.cmake\")
set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
@@ -49,7 +50,8 @@ endif ()
add_test(NAME export_interfaces_build
COMMAND
"${CMAKE_COMMAND}"
- "-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
+ "-Dexpected_source_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
+ "-Dexpected_binary_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/bmi"
"-Dexport_interfaces_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_interfaces"
${generator}
-S "${CMAKE_CURRENT_SOURCE_DIR}/test"
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-install/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-install/importable.cxx
index e0b1872..8dfc41b 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-install/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-install/importable.cxx
@@ -1,6 +1,8 @@
export module importable;
+extern "C++" {
int forwarding();
+}
export int from_import()
{
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt
index 6145210..7079256 100644
--- a/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)
project(cxx_modules_library NONE)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
find_package(export_interfaces REQUIRED)
@@ -19,14 +19,14 @@ endif ()
get_property(file_set_files TARGET CXXModules::export_interfaces
PROPERTY CXX_MODULE_SET_modules)
-if (NOT file_set_files STREQUAL "${expected_dir}/importable.cxx")
+if (NOT file_set_files STREQUAL "${expected_source_dir}/importable.cxx")
message(FATAL_ERROR
"Incorrect exported file set paths in CXXModules::export_interfaces`: `${file_set_files}`")
endif ()
-get_property(imported_modules_set TARGET CXXModules::export_interfaces
- PROPERTY IMPORTED_CXX_MODULES_DEBUG SET)
-if (imported_modules_set)
+get_property(imported_modules TARGET CXXModules::export_interfaces
+ PROPERTY IMPORTED_CXX_MODULES_DEBUG)
+if (NOT imported_modules STREQUAL "importable=${expected_source_dir}/importable.cxx")
message(FATAL_ERROR
- "Unexpected C++ modules specified.")
+ "Incorrect exported modules in CXXModules::export_interfaces`: `${imported_modules}`")
endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-stderr.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+ CMake's C\+\+ module support is experimental. It is meant only for
+ experimentation and feedback to CMake developers.
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/CMakeLists.txt
new file mode 100644
index 0000000..7633bec
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/CMakeLists.txt
@@ -0,0 +1,53 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_export_interfaces_no_properties CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_library(export_interfaces_no_properties STATIC)
+target_sources(export_interfaces_no_properties
+ PRIVATE
+ forward.cxx
+ PRIVATE
+ FILE_SET modules_private TYPE CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ private.cxx
+ PUBLIC
+ FILE_SET modules TYPE CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ importable.cxx)
+target_compile_features(export_interfaces_no_properties PUBLIC cxx_std_20)
+
+install(TARGETS export_interfaces_no_properties
+ EXPORT CXXModules
+ FILE_SET modules DESTINATION "lib/cxx/miu")
+export(EXPORT CXXModules
+ NAMESPACE CXXModules::
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces_no_properties-targets.cmake")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces_no_properties-config.cmake"
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces_no_properties-targets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
+")
+
+set(generator
+ -G "${CMAKE_GENERATOR}")
+if (CMAKE_GENERATOR_TOOLSET)
+ list(APPEND generator
+ -T "${CMAKE_GENERATOR_TOOLSET}")
+endif ()
+if (CMAKE_GENERATOR_PLATFORM)
+ list(APPEND generator
+ -A "${CMAKE_GENERATOR_PLATFORM}")
+endif ()
+
+add_test(NAME export_interfaces_build
+ COMMAND
+ "${CMAKE_COMMAND}"
+ "-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
+ "-Dexport_interfaces_no_properties_DIR=${CMAKE_CURRENT_BINARY_DIR}"
+ ${generator}
+ -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
+ -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx
new file mode 100644
index 0000000..7f53271
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx
@@ -0,0 +1,6 @@
+import priv;
+
+int forwarding()
+{
+ return from_private();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx
new file mode 100644
index 0000000..8dfc41b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx
@@ -0,0 +1,10 @@
+export module importable;
+
+extern "C++" {
+int forwarding();
+}
+
+export int from_import()
+{
+ return forwarding();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx
new file mode 100644
index 0000000..c5b719a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx
@@ -0,0 +1,6 @@
+export module priv;
+
+export int from_private()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/test/CMakeLists.txt
new file mode 100644
index 0000000..9cdc80a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/test/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_library NONE)
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
+
+find_package(export_interfaces_no_properties REQUIRED)
+
+if (NOT TARGET CXXModules::export_interfaces_no_properties)
+ message(FATAL_ERROR
+ "Missing imported target")
+endif ()
+
+get_property(file_sets TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY INTERFACE_CXX_MODULE_SETS)
+if (NOT file_sets STREQUAL "modules")
+ message(FATAL_ERROR
+ "Incorrect exported file sets in `CXXModules::export_interfaces_no_properties`: `${file_sets}`")
+endif ()
+
+get_property(file_set_files TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY CXX_MODULE_SET_modules)
+if (NOT file_set_files STREQUAL "${expected_dir}/importable.cxx")
+ message(FATAL_ERROR
+ "Incorrect exported file set paths in CXXModules::export_interfaces_no_properties`: `${file_set_files}`")
+endif ()
+
+get_property(imported_modules_set TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY IMPORTED_CXX_MODULES_DEBUG SET)
+if (imported_modules_set)
+ message(FATAL_ERROR
+ "Unexpected C++ modules specified.")
+endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-stderr.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+ CMake's C\+\+ module support is experimental. It is meant only for
+ experimentation and feedback to CMake developers.
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/CMakeLists.txt
new file mode 100644
index 0000000..75f2440
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_export_interfaces CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_library(export_interfaces_no_properties STATIC)
+target_sources(export_interfaces_no_properties
+ PRIVATE
+ forward.cxx
+ PRIVATE
+ FILE_SET modules_private TYPE CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ private.cxx
+ PUBLIC
+ FILE_SET modules TYPE CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ importable.cxx)
+target_compile_features(export_interfaces_no_properties PUBLIC cxx_std_20)
+
+install(TARGETS export_interfaces_no_properties
+ EXPORT CXXModules
+ FILE_SET modules DESTINATION "lib/cxx/miu")
+install(EXPORT CXXModules
+ NAMESPACE CXXModules::
+ DESTINATION "lib/cmake/export_interfaces_no_properties"
+ FILE "export_interfaces_no_properties-targets.cmake")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces_no_properties-config.cmake"
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces_no_properties-targets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
+")
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces_no_properties-config.cmake"
+ DESTINATION "lib/cmake/export_interfaces_no_properties")
+
+set(generator
+ -G "${CMAKE_GENERATOR}")
+if (CMAKE_GENERATOR_TOOLSET)
+ list(APPEND generator
+ -T "${CMAKE_GENERATOR_TOOLSET}")
+endif ()
+if (CMAKE_GENERATOR_PLATFORM)
+ list(APPEND generator
+ -A "${CMAKE_GENERATOR_PLATFORM}")
+endif ()
+
+add_test(NAME export_interfaces_build
+ COMMAND
+ "${CMAKE_COMMAND}"
+ "-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
+ "-Dexport_interfaces_no_properties_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_interfaces_no_properties"
+ ${generator}
+ -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
+ -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx
new file mode 100644
index 0000000..7f53271
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx
@@ -0,0 +1,6 @@
+import priv;
+
+int forwarding()
+{
+ return from_private();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx
new file mode 100644
index 0000000..8dfc41b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx
@@ -0,0 +1,10 @@
+export module importable;
+
+extern "C++" {
+int forwarding();
+}
+
+export int from_import()
+{
+ return forwarding();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx
new file mode 100644
index 0000000..c5b719a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx
@@ -0,0 +1,6 @@
+export module priv;
+
+export int from_private()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/test/CMakeLists.txt
new file mode 100644
index 0000000..9cdc80a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/test/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_library NONE)
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
+
+find_package(export_interfaces_no_properties REQUIRED)
+
+if (NOT TARGET CXXModules::export_interfaces_no_properties)
+ message(FATAL_ERROR
+ "Missing imported target")
+endif ()
+
+get_property(file_sets TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY INTERFACE_CXX_MODULE_SETS)
+if (NOT file_sets STREQUAL "modules")
+ message(FATAL_ERROR
+ "Incorrect exported file sets in `CXXModules::export_interfaces_no_properties`: `${file_sets}`")
+endif ()
+
+get_property(file_set_files TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY CXX_MODULE_SET_modules)
+if (NOT file_set_files STREQUAL "${expected_dir}/importable.cxx")
+ message(FATAL_ERROR
+ "Incorrect exported file set paths in CXXModules::export_interfaces_no_properties`: `${file_set_files}`")
+endif ()
+
+get_property(imported_modules_set TARGET CXXModules::export_interfaces_no_properties
+ PROPERTY IMPORTED_CXX_MODULES_DEBUG SET)
+if (imported_modules_set)
+ message(FATAL_ERROR
+ "Unexpected C++ modules specified.")
+endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx
index b872ae9..3b3d313 100644
--- a/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx
@@ -1,5 +1,5 @@
export module importable;
-import : internal_partition;
+import :internal_partition;
#include "internal-partitions_export.h"
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx
index b15f53c..c828612 100644
--- a/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx
@@ -1,4 +1,4 @@
-module importable : internal_partition;
+module importable:internal_partition;
int from_partition()
{
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx
index d0ac2f4..fbd5f90 100644
--- a/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx
+++ b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx
@@ -1,5 +1,5 @@
export module importable;
-export import : partition;
+export import :partition;
#include "partitions_export.h"
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx
index a47a4fd..20131cf 100644
--- a/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx
+++ b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx
@@ -1,4 +1,4 @@
-export module importable : partition;
+export module importable:partition;
#include "partitions_export.h"
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties-stderr.txt b/Tests/RunCMake/CXXModules/examples/scan_properties-stderr.txt
new file mode 100644
index 0000000..2cb5957
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:25 \(target_sources\):
+ CMake's C\+\+ module support is experimental. It is meant only for
+ experimentation and feedback to CMake developers.
+This warning is for project developers. Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+ C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+ experimental. It is meant only for compiler developers to try.
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt
new file mode 100644
index 0000000..f2f1c38
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 3.24)
+project(scan_properties CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+set(scanning_control 1)
+if (CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(scanning_control 0)
+endif ()
+
+# To detect that not-to-be scanned sources are not scanned, add a `-D` to the
+# scan flags so that the files can detect whether scanning happened and error
+# if not.
+string(APPEND CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG
+ " -DCMAKE_SCANNED_THIS_SOURCE")
+string(APPEND CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
+ " -DCMAKE_SCANNED_THIS_SOURCE")
+
+set_property(SOURCE always_scan.cxx
+ PROPERTY CXX_SCAN_FOR_MODULES 1)
+set_property(SOURCE never_scan.cxx
+ PROPERTY CXX_SCAN_FOR_MODULES 0)
+
+add_executable(scans_everything)
+target_sources(scans_everything
+ PRIVATE
+ main.cxx
+ join.cxx
+ always_scan.cxx
+ never_scan.cxx
+ PRIVATE
+ FILE_SET CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ module.cxx)
+target_compile_features(scans_everything PRIVATE cxx_std_20)
+target_compile_definitions(scans_everything PRIVATE SCAN_AT_TARGET_LEVEL=1)
+target_compile_definitions(scans_everything PRIVATE "SCANNING_CONTROL=${scanning_control}")
+
+set(CMAKE_CXX_SCAN_FOR_MODULES 0)
+
+add_executable(no_scan_everything)
+target_sources(no_scan_everything
+ PRIVATE
+ main.cxx
+ join.cxx
+ always_scan.cxx
+ never_scan.cxx
+ PRIVATE
+ FILE_SET CXX_MODULES
+ BASE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ FILES
+ module.cxx)
+target_compile_features(no_scan_everything PRIVATE cxx_std_20)
+target_compile_definitions(no_scan_everything PRIVATE SCAN_AT_TARGET_LEVEL=0)
+target_compile_definitions(no_scan_everything PRIVATE "SCANNING_CONTROL=${scanning_control}")
+
+add_test(NAME scanned COMMAND scans_everything)
+add_test(NAME unscanned COMMAND no_scan_everything)
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/always_scan.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/always_scan.cxx
new file mode 100644
index 0000000..c3d449e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/always_scan.cxx
@@ -0,0 +1,12 @@
+#if SCANNING_CONTROL
+# ifndef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should have been scanned"
+# endif
+#endif
+
+import M;
+
+int scanned_file()
+{
+ return from_module();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/join.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/join.cxx
new file mode 100644
index 0000000..4ba23a6
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/join.cxx
@@ -0,0 +1,19 @@
+#if SCANNING_CONTROL
+# if SCAN_AT_TARGET_LEVEL
+# ifndef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should have been scanned"
+# endif
+# else
+# ifdef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should not have been scanned"
+# endif
+# endif
+#endif
+
+int scanned_file();
+int never_scan();
+
+int join()
+{
+ return scanned_file() + never_scan();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/main.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/main.cxx
new file mode 100644
index 0000000..2c7ec3e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/main.cxx
@@ -0,0 +1,18 @@
+#if SCANNING_CONTROL
+# if SCAN_AT_TARGET_LEVEL
+# ifndef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should have been scanned"
+# endif
+# else
+# ifdef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should not have been scanned"
+# endif
+# endif
+#endif
+
+int join();
+
+int main(int argc, char** argv)
+{
+ return join();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/module.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/module.cxx
new file mode 100644
index 0000000..fe84261
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/module.cxx
@@ -0,0 +1,12 @@
+#if SCANNING_CONTROL
+# ifndef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should have been scanned"
+# endif
+#endif
+
+export module M;
+
+export int from_module()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx b/Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx
new file mode 100644
index 0000000..b47510b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/scan_properties/never_scan.cxx
@@ -0,0 +1,10 @@
+#if SCANNING_CONTROL
+# ifdef CMAKE_SCANNED_THIS_SOURCE
+# error "This file should not have been scanned"
+# endif
+#endif
+
+int never_scan()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx
index be77b0d..cab19ec 100644
--- a/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx
+++ b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx
@@ -1,6 +1,6 @@
#ifdef _MSC_VER
// Only MSVC supports this pattern.
-module M : internal_part;
+module M:internal_part;
#else
module M;
#endif
diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx
index fa82afb..0dc749f 100644
--- a/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx
+++ b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx
@@ -1,3 +1,3 @@
-module M : internal_part;
+module M:internal_part;
int i();
diff --git a/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx
index 46d5d9f..f3b6ba8 100644
--- a/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx
+++ b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx
@@ -1,11 +1,11 @@
#ifdef _MSC_VER
// Only MSVC supports this pattern.
-module M : part;
+module M:part;
#else
module M;
#endif
-import M : internal_part;
+import M:internal_part;
int p()
{
diff --git a/Tests/RunCMake/CXXModules/sources/module-part.cxx b/Tests/RunCMake/CXXModules/sources/module-part.cxx
index 137c16f..307781b 100644
--- a/Tests/RunCMake/CXXModules/sources/module-part.cxx
+++ b/Tests/RunCMake/CXXModules/sources/module-part.cxx
@@ -1,3 +1,3 @@
-export module M : part;
+export module M:part;
int p();
diff --git a/Tests/RunCMake/CXXModules/sources/module.cxx b/Tests/RunCMake/CXXModules/sources/module.cxx
index a631354..37eedeb 100644
--- a/Tests/RunCMake/CXXModules/sources/module.cxx
+++ b/Tests/RunCMake/CXXModules/sources/module.cxx
@@ -1,5 +1,5 @@
export module M;
-export import M : part;
-import M : internal_part;
+export import M:part;
+import M:internal_part;
int f();
diff --git a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake
new file mode 100644
index 0000000..23b3006
--- /dev/null
+++ b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagSwift.cmake
@@ -0,0 +1,21 @@
+enable_language (Swift)
+include(CheckCompilerFlag)
+
+set(Swift 1)
+
+# test that the check uses an isolated locale
+set(_env_LC_ALL "${LC_ALL}")
+set(ENV{LC_ALL} "BAD")
+
+check_compiler_flag(Swift "-foo-as-blarpy" SHOULD_FAIL)
+if(SHOULD_FAIL)
+ message(SEND_ERROR "invalid Swift compile flag didn't fail.")
+endif()
+
+check_compiler_flag(Swift "-parseable-output" SHOULD_WORK)
+if(NOT SHOULD_WORK)
+ message(SEND_ERROR "Swift compiler flag '-parseable-output' check failed")
+endif()
+
+# Reset locale
+set(ENV{LC_ALL} ${_env_LC_ALL})
diff --git a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
index b0e025c..81429a6 100644
--- a/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CheckCompilerFlag/RunCMakeTest.cmake
@@ -32,3 +32,7 @@ endif()
if(APPLE)
run_cmake(HeaderpadWorkaround)
endif()
+
+if(CMake_TEST_Swift)
+ run_cmake(CheckCompilerFlagSwift)
+endif()
diff --git a/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake
new file mode 100644
index 0000000..767fa69
--- /dev/null
+++ b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesSwift.cmake
@@ -0,0 +1,15 @@
+enable_language(Swift)
+include(CheckSourceCompiles)
+
+set(Swift 1) # test that this is tolerated
+
+check_source_compiles(Swift "baz()" SHOULD_FAIL)
+
+if(SHOULD_FAIL)
+ message(SEND_ERROR "invalid Swift source didn't fail.")
+endif()
+
+check_source_compiles(Swift "print(\"Hello, CMake\")" SHOULD_BUILD)
+if(NOT SHOULD_BUILD)
+ message(SEND_ERROR "Test failed for valid Swift source.")
+endif()
diff --git a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
index df77d3d..2ed3e36 100644
--- a/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CheckSourceCompiles/RunCMakeTest.cmake
@@ -31,3 +31,7 @@ endif()
if(CMake_TEST_HIP)
run_cmake(CheckSourceCompilesHIP)
endif()
+
+if(CMake_TEST_Swift)
+ run_cmake(CheckSourceCompilesSwift)
+endif()
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake
new file mode 100644
index 0000000..97ec52b
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir-Build-check.cmake
@@ -0,0 +1,35 @@
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml"
+ )
+else()
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml"
+ )
+endif()
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake
new file mode 100644
index 0000000..2b278da
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
+set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy)
+set(files ${CMAKE_CURRENT_SOURCE_DIR}/main.c ${CMAKE_CURRENT_SOURCE_DIR}/extra.c)
+add_executable(main ${files})
+add_subdirectory(export_fixes_subdir)
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake
new file mode 100644
index 0000000..f65d33c
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2-Build-check.cmake
@@ -0,0 +1,35 @@
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml"
+ )
+else()
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml"
+ )
+endif()
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake
new file mode 100644
index 0000000..f65d33c
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2-check.cmake
@@ -0,0 +1,35 @@
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/Debug/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/Debug/__/extra.c.obj.yaml"
+ )
+else()
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/clang-tidy/CMakeFiles/main.dir/extra.c.obj.yaml"
+ )
+ assert_any_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/main.c.obj.yaml"
+ )
+ assert_no_file_exists(
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.o.yaml"
+ "${RunCMake_TEST_BINARY_DIR}/export_fixes_subdir/clang-tidy/export_fixes_subdir/CMakeFiles/subdir.dir/__/extra.c.obj.yaml"
+ )
+endif()
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake
new file mode 100644
index 0000000..c81c49a
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
+set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy)
+set(files ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
+add_executable(main ${files})
+add_subdirectory(export_fixes_subdir)
diff --git a/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake b/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake
index 5e3fbc4..01dbb61 100644
--- a/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ClangTidy/RunCMakeTest.cmake
@@ -30,3 +30,55 @@ if (NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
endif()
run_tidy(C-bad)
run_tidy(compdb)
+
+function(any_file_exists varname)
+ foreach(filename IN LISTS ARGN)
+ if(EXISTS "${filename}")
+ set("${varname}" 1 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ set("${varname}" 0 PARENT_SCOPE)
+endfunction()
+
+function(assert_any_file_exists)
+ any_file_exists(exists ${ARGN})
+ if(NOT exists)
+ string(APPEND RunCMake_TEST_FAILED "Expected one of the following files to exist but they do not:\n")
+ foreach(filename IN LISTS ARGN)
+ string(APPEND RunCMake_TEST_FAILED " ${filename}\n")
+ endforeach()
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(assert_no_file_exists)
+ any_file_exists(exists ${ARGN})
+ if(exists)
+ string(APPEND RunCMake_TEST_FAILED "Expected none of the following files to exist but one of them does:\n")
+ foreach(filename IN LISTS ARGN)
+ string(APPEND RunCMake_TEST_FAILED " ${filename}\n")
+ endforeach()
+ set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(run_tidy_export_fixes)
+ # Use a single build tree for tests without cleaning.
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExportFixesDir-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(ExportFixesDir)
+
+ set(RunCMake_TEST_OUTPUT_MERGE 1)
+ run_cmake_command(ExportFixesDir-Build ${CMAKE_COMMAND} --build . --config Debug)
+ unset(RunCMake_TEST_OUTPUT_MERGE)
+
+ run_cmake(ExportFixesDir2)
+
+ set(RunCMake_TEST_OUTPUT_MERGE 1)
+ run_cmake_command(ExportFixesDir2-Build ${CMAKE_COMMAND} --build . --config Debug)
+ unset(RunCMake_TEST_OUTPUT_MERGE)
+endfunction()
+run_tidy_export_fixes()
diff --git a/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt b/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt
new file mode 100644
index 0000000..af2db88
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/export_fixes_subdir/CMakeLists.txt
@@ -0,0 +1 @@
+add_executable(subdir ${files})
diff --git a/Tests/RunCMake/ClangTidy/extra.c b/Tests/RunCMake/ClangTidy/extra.c
new file mode 100644
index 0000000..d235550
--- /dev/null
+++ b/Tests/RunCMake/ClangTidy/extra.c
@@ -0,0 +1,3 @@
+void extra(void)
+{
+}
diff --git a/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt b/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt
index adc125b..ce1cce3 100644
--- a/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt
+++ b/Tests/RunCMake/CommandLine/C_buildsrcdir/initial-cache.txt
@@ -1,3 +1,5 @@
+set(CMAKE_MINIMUM_REQUIRED_VERSION "" CACHE STRING "")
+
# Used to verify that the values match what is passed via -S and -B, and are retained in cache.
set(INITIAL_SOURCE_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "defined in initial.cmake")
set(INITIAL_BINARY_DIR "${CMAKE_BINARY_DIR}" CACHE PATH "defined in initial.cmake")
diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake
new file mode 100644
index 0000000..d638fda
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-check.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "${RunCMake_BINARY_DIR}/tidy-fixes.yaml")
+ string(APPEND RunCMake_TEST_FAILED "Expected ${RunCMake_BINARY_DIR}/tidy-fixes.yaml not to exist but it does")
+endif()
diff --git a/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake
new file mode 100644
index 0000000..1e89ffe
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E___run_co_compile-tidy-remove-fixes-prep.cmake
@@ -0,0 +1 @@
+file(TOUCH "${RunCMake_BINARY_DIR}/tidy-fixes.yaml")
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index 1452c9b..597dbd4 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":4}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":5}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt
+++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-result.txt
diff --git a/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt
new file mode 100644
index 0000000..9504216
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy-t-argument-target-is-file-stderr.txt
@@ -0,0 +1 @@
+^Error: Target \(for copy command\).* is not a directory.$
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt
new file mode 100644
index 0000000..cdfe857
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stderr.txt
@@ -0,0 +1 @@
+CMake Error: CMAKE_GENERATOR was set but the specified generator doesn't exist. Using CMake default.
diff --git a/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt
new file mode 100644
index 0000000..075c48c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-bad-help-stdout.txt
@@ -0,0 +1,2 @@
+Generators.*
+\* (Unix Makefiles|Visual Studio).*
diff --git a/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt
new file mode 100644
index 0000000..ece6e5d
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/Envgen-ninja-multi-help-stdout.txt
@@ -0,0 +1 @@
+\* Ninja Multi-Config[ ]+= Generates build-<Config>.ninja files.
diff --git a/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args-stdout.txt b/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args-stdout.txt
new file mode 100644
index 0000000..95304ab
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args-stdout.txt
@@ -0,0 +1,10 @@
+^-- CMAKE_ARGC='6'
+-- CMAKE_ARGV1='-P'
+-- CMAKE_ARGV2='[^']*/Tests/RunCMake/CommandLine/P_arbitrary_args.cmake'
+-- CMAKE_ARGV3='--'
+-- CMAKE_ARGV4='-P'
+-- CMAKE_ARGV5='[^']*/Tests/RunCMake/CommandLine/non_existing.cmake'
+-- CMAKE_ARGV6=''
+-- CMAKE_ARGV7=''
+-- CMAKE_ARGV8=''
+-- CMAKE_ARGV9=''$
diff --git a/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args_2-stdout.txt b/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args_2-stdout.txt
new file mode 100644
index 0000000..ad386bd
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/P_P_in_arbitrary_args_2-stdout.txt
@@ -0,0 +1,10 @@
+^-- CMAKE_ARGC='6'
+-- CMAKE_ARGV1='-P'
+-- CMAKE_ARGV2='[^']*/Tests/RunCMake/CommandLine/P_arbitrary_args.cmake'
+-- CMAKE_ARGV3='--'
+-- CMAKE_ARGV4='-P'
+-- CMAKE_ARGV5='-o'
+-- CMAKE_ARGV6=''
+-- CMAKE_ARGV7=''
+-- CMAKE_ARGV8=''
+-- CMAKE_ARGV9=''$
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index a2eeddf..943be24 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -47,6 +47,7 @@ run_cmake_command(E___run_co_compile-no-iwyu ${CMAKE_COMMAND} -E __run_co_compil
run_cmake_command(E___run_co_compile-bad-iwyu ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist -- command-does-not-exist)
run_cmake_command(E___run_co_compile-no--- ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist command-does-not-exist)
run_cmake_command(E___run_co_compile-no-cc ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist --)
+run_cmake_command(E___run_co_compile-tidy-remove-fixes ${CMAKE_COMMAND} -E __run_co_compile "--tidy=${CMAKE_COMMAND}\\;-E\\;true\\;--export-fixes=${RunCMake_BINARY_DIR}/tidy-fixes.yaml" -- ${CMAKE_COMMAND} -E true)
run_cmake_command(G_no-arg ${CMAKE_COMMAND} -B DummyBuildDir -G)
run_cmake_command(G_bad-arg ${CMAKE_COMMAND} -B DummyBuildDir -G NoSuchGenerator)
@@ -54,10 +55,14 @@ run_cmake_command(P_no-arg ${CMAKE_COMMAND} -P)
run_cmake_command(P_no-file ${CMAKE_COMMAND} -P nosuchscriptfile.cmake)
run_cmake_command(P_args ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_args.cmake" relative/path "${RunCMake_SOURCE_DIR}")
run_cmake_command(P_arbitrary_args ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_arbitrary_args.cmake" -- -DFOO -S -B --fresh --version)
+run_cmake_command(P_P_in_arbitrary_args ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_arbitrary_args.cmake" -- -P "${RunCMake_SOURCE_DIR}/non_existing.cmake")
+run_cmake_command(P_P_in_arbitrary_args_2 ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_arbitrary_args.cmake" -- -P -o)
run_cmake_command(P_fresh ${CMAKE_COMMAND} -P "${RunCMake_SOURCE_DIR}/P_fresh.cmake" --fresh)
run_cmake_command(build-no-dir
${CMAKE_COMMAND} --build)
+run_cmake_command(build-no-dir2
+ ${CMAKE_COMMAND} --build --target=invalid)
run_cmake_command(build-no-cache
${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR})
run_cmake_command(build-unknown-command-short
@@ -349,6 +354,13 @@ function(run_EnvironmentGenerator)
run_cmake_command(Envgen-bad ${CMAKE_COMMAND} -G)
unset(ENV{CMAKE_GENERATOR})
+ # Honor CMAKE_GENERATOR env var in --help output
+ set(ENV{CMAKE_GENERATOR} "Ninja Multi-Config")
+ run_cmake_command(Envgen-ninja-multi-help ${CMAKE_COMMAND} --help)
+ set(ENV{CMAKE_GENERATOR} "NoSuchGenerator")
+ run_cmake_command(Envgen-bad-help ${CMAKE_COMMAND} --help)
+ unset(ENV{CMAKE_GENERATOR})
+
if(RunCMake_GENERATOR MATCHES "Visual Studio.*")
set(ENV{CMAKE_GENERATOR} "${RunCMake_GENERATOR}")
run_cmake_command(Envgen ${CMAKE_COMMAND} ${source_dir})
@@ -567,6 +579,12 @@ run_cmake_command(E_copy-three-source-files-target-is-file
${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt)
run_cmake_command(E_copy-two-good-and-one-bad-source-files-target-is-directory
${CMAKE_COMMAND} -E copy ${in}/f1.txt ${in}/not_existing_file.bad ${in}/f3.txt ${out})
+run_cmake_command(E_copy-t-argument
+ ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out} ${in}/f3.txt)
+run_cmake_command(E_copy-t-argument-target-is-file
+ ${CMAKE_COMMAND} -E copy ${in}/f1.txt -t ${out}/f1.txt ${in}/f3.txt)
+run_cmake_command(E_copy-t-argument-no-source-files
+ ${CMAKE_COMMAND} -E copy -t ${out})
run_cmake_command(E_copy_if_different-one-source-directory-target-is-directory
${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${out})
run_cmake_command(E_copy_if_different-three-source-files-target-is-directory
@@ -577,6 +595,15 @@ unset(in)
unset(out)
set(in ${RunCMake_SOURCE_DIR}/copy_input)
+set(out ${RunCMake_BINARY_DIR}/copy_directory_different_output)
+file(REMOVE_RECURSE "${out}")
+file(MAKE_DIRECTORY ${out})
+run_cmake_command(E_copy_directory_if_different
+ ${CMAKE_COMMAND} -E copy_directory_if_different ${in} ${out})
+unset(in)
+unset(out)
+
+set(in ${RunCMake_SOURCE_DIR}/copy_input)
set(out ${RunCMake_BINARY_DIR}/copy_directory_output)
set(outfile ${out}/file_for_test.txt)
file(REMOVE_RECURSE "${out}")
@@ -940,6 +967,7 @@ unset(RunCMake_TEST_OPTIONS)
set(RunCMake_TEST_OPTIONS --trace)
run_cmake(trace)
+run_cmake(trace-try_compile)
unset(RunCMake_TEST_OPTIONS)
set(RunCMake_TEST_OPTIONS --trace-expand)
@@ -952,6 +980,7 @@ unset(RunCMake_TEST_OPTIONS)
set(RunCMake_TEST_OPTIONS --trace-redirect=${RunCMake_BINARY_DIR}/redirected.trace)
run_cmake(trace-redirect)
+run_cmake(trace-try_compile-redirect)
unset(RunCMake_TEST_OPTIONS)
set(RunCMake_TEST_OPTIONS --trace-redirect=/no/such/file.txt)
diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt b/Tests/RunCMake/CommandLine/build-no-dir2-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-result.txt
+++ b/Tests/RunCMake/CommandLine/build-no-dir2-result.txt
diff --git a/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt b/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt
new file mode 100644
index 0000000..4811bea
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/build-no-dir2-stderr.txt
@@ -0,0 +1 @@
+^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/cmake_depends/.gitattributes b/Tests/RunCMake/CommandLine/cmake_depends/.gitattributes
index d9a4db4..9c22288 100644
--- a/Tests/RunCMake/CommandLine/cmake_depends/.gitattributes
+++ b/Tests/RunCMake/CommandLine/cmake_depends/.gitattributes
@@ -1,2 +1,2 @@
# Do not format a source encoded in UTF-16.
-test_UTF-16LE.h -format.clang-format-6.0
+test_UTF-16LE.h -format.clang-format
diff --git a/Tests/RunCMake/CommandLine/cmake_depends/test.c b/Tests/RunCMake/CommandLine/cmake_depends/test.c
index 92c056f..5b42255 100644
--- a/Tests/RunCMake/CommandLine/cmake_depends/test.c
+++ b/Tests/RunCMake/CommandLine/cmake_depends/test.c
@@ -1,2 +1,3 @@
#include "test.h"
+
#include "test_UTF-16LE.h"
diff --git a/Tests/RunCMake/CommandLine/compare_files/.gitattributes b/Tests/RunCMake/CommandLine/compare_files/.gitattributes
index 91d5c10..d03da96 100644
--- a/Tests/RunCMake/CommandLine/compare_files/.gitattributes
+++ b/Tests/RunCMake/CommandLine/compare_files/.gitattributes
@@ -1,2 +1,2 @@
-crlf eol=crlf
-lf eol=lf
+crlf -text -whitespace
+lf -text
diff --git a/Tests/RunCMake/CommandLine/compare_files/crlf b/Tests/RunCMake/CommandLine/compare_files/crlf
index a29bdeb..495181c 100644
--- a/Tests/RunCMake/CommandLine/compare_files/crlf
+++ b/Tests/RunCMake/CommandLine/compare_files/crlf
@@ -1 +1 @@
-line1
+line1
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake
new file mode 100644
index 0000000..94a7c95
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect-check.cmake
@@ -0,0 +1,13 @@
+file(READ ${RunCMake_SOURCE_DIR}/trace-try_compile-stderr.txt expected_content)
+string(REGEX REPLACE "\n+$" "" expected_content "${expected_content}")
+
+file(READ ${RunCMake_BINARY_DIR}/redirected.trace actual_content)
+string(REGEX REPLACE "\r\n" "\n" actual_content "${actual_content}")
+string(REGEX REPLACE "\n+$" "" actual_content "${actual_content}")
+if(NOT "${actual_content}" MATCHES "${expected_content}")
+ set(RunCMake_TEST_FAILED
+ "Trace file content does not match that expected."
+ "Expected to match:\n${expected_content}\n"
+ "Actual content:\n${actual_content}\n"
+ )
+endif()
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake
new file mode 100644
index 0000000..982cb89
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-redirect.cmake
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.24)
+project(test C)
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt
new file mode 100644
index 0000000..1674b8f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile-stderr.txt
@@ -0,0 +1,4 @@
+.*Modules/CMakeDetermineCompilerABI.cmake\([0-9]+\): try_compile\([^)]+\)
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): cmake_minimum_required.*
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): project\(CMAKE_TRY_COMPILE.*
+.*Tests/RunCMake/CommandLine/trace-try_compile(-redirect)?-build/CMakeFiles/CMakeScratch/TryCompile-[^/]+/CMakeLists.txt\([0-9]+\): add_executable\(cmTC_.*
diff --git a/Tests/RunCMake/CommandLine/trace-try_compile.cmake b/Tests/RunCMake/CommandLine/trace-try_compile.cmake
new file mode 100644
index 0000000..982cb89
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/trace-try_compile.cmake
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.24)
+project(test C)
diff --git a/Tests/RunCMake/CompileDefinitions/RemoveLeadingMinusD.cmake b/Tests/RunCMake/CompileDefinitions/RemoveLeadingMinusD.cmake
new file mode 100644
index 0000000..3db6cff1f
--- /dev/null
+++ b/Tests/RunCMake/CompileDefinitions/RemoveLeadingMinusD.cmake
@@ -0,0 +1,11 @@
+
+enable_language(C)
+
+set_property(SOURCE foo.c PROPERTY COMPILE_DEFINITIONS -DDEF0 "$<1:-DDEF1>")
+
+add_library(lib1 foo.c)
+set_property(TARGET lib1 PROPERTY COMPILE_DEFINITIONS -DDEF2 "$<1:-DDEF3>")
+set_property(TARGET lib1 PROPERTY INTERFACE_COMPILE_DEFINITIONS -DDEF4 "$<1:-DDEF5>")
+
+add_library(lib2 foo.c)
+target_link_libraries(lib2 PRIVATE lib1)
diff --git a/Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake b/Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake
index 233fe34..eebcd22 100644
--- a/Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CompileDefinitions/RunCMakeTest.cmake
@@ -1,3 +1,16 @@
include(RunCMake)
run_cmake(SetEmpty)
+
+
+macro(run_cmake_build test)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test} ${CMAKE_COMMAND} --build . --config Release)
+
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+run_cmake(RemoveLeadingMinusD)
+run_cmake_build(RemoveLeadingMinusD)
diff --git a/Tests/RunCMake/CompileDefinitions/foo.c b/Tests/RunCMake/CompileDefinitions/foo.c
new file mode 100644
index 0000000..74a86e1
--- /dev/null
+++ b/Tests/RunCMake/CompileDefinitions/foo.c
@@ -0,0 +1,4 @@
+
+void foo()
+{
+}
diff --git a/Tests/RunCMake/Configure/CopyFileABI-stdout.txt b/Tests/RunCMake/Configure/CopyFileABI-stdout.txt
index 6a856a4..2176554 100644
--- a/Tests/RunCMake/Configure/CopyFileABI-stdout.txt
+++ b/Tests/RunCMake/Configure/CopyFileABI-stdout.txt
@@ -1,4 +1,4 @@
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done.*
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
diff --git a/Tests/RunCMake/Configure/ErrorLogs-stderr.txt b/Tests/RunCMake/Configure/ErrorLogs-stderr.txt
deleted file mode 100644
index 4eee45d..0000000
--- a/Tests/RunCMake/Configure/ErrorLogs-stderr.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-CMake Error at ErrorLogs.cmake:3 \(message\):
- Some error!
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/Configure/ErrorLogs-stdout.txt b/Tests/RunCMake/Configure/ErrorLogs-stdout.txt
deleted file mode 100644
index c467b62..0000000
--- a/Tests/RunCMake/Configure/ErrorLogs-stdout.txt
+++ /dev/null
@@ -1,3 +0,0 @@
--- Configuring incomplete, errors occurred!
-See also ".*/Tests/RunCMake/Configure/ErrorLogs-build/CMakeFiles/CMakeOutput\.log"\.
-See also ".*/Tests/RunCMake/Configure/ErrorLogs-build/CMakeFiles/CMakeError\.log"\.
diff --git a/Tests/RunCMake/Configure/ErrorLogs.cmake b/Tests/RunCMake/Configure/ErrorLogs.cmake
deleted file mode 100644
index e8cf062..0000000
--- a/Tests/RunCMake/Configure/ErrorLogs.cmake
+++ /dev/null
@@ -1,3 +0,0 @@
-file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Some detailed error information!\n")
-message(SEND_ERROR "Some error!")
diff --git a/Tests/RunCMake/Configure/RunCMakeTest.cmake b/Tests/RunCMake/Configure/RunCMakeTest.cmake
index 750fa3c..df6849e 100644
--- a/Tests/RunCMake/Configure/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Configure/RunCMakeTest.cmake
@@ -3,7 +3,6 @@ include(RunCMake)
run_cmake(ContinueAfterError)
run_cmake(CopyFileABI)
run_cmake(CustomTargetAfterError)
-run_cmake(ErrorLogs)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/RerunCMake-build)
diff --git a/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake
new file mode 100644
index 0000000..94076bb
--- /dev/null
+++ b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-export.cmake
@@ -0,0 +1,14 @@
+enable_language(C)
+
+add_library(mainlib STATIC foo.c)
+target_compile_definitions(mainlib INTERFACE
+ $<BUILD_LOCAL_INTERFACE:BUILD_LOCAL_INTERFACE>
+ $<BUILD_INTERFACE:BUILD_INTERFACE>
+ $<INSTALL_INTERFACE:INSTALL_INTERFACE>
+ )
+add_library(locallib STATIC locallib.c)
+target_link_libraries(locallib PRIVATE mainlib)
+
+install(TARGETS mainlib EXPORT export)
+install(EXPORT export DESTINATION lib/cmake/install FILE install-config.cmake NAMESPACE install::)
+export(EXPORT export FILE build-config.cmake NAMESPACE build::)
diff --git a/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake
new file mode 100644
index 0000000..3fe5fae
--- /dev/null
+++ b/Tests/RunCMake/ExportImport/BuildInstallInterfaceGenex-import.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+find_package(build REQUIRED)
+find_package(install REQUIRED)
+
+add_library(buildlib STATIC buildlib.c)
+target_link_libraries(buildlib PRIVATE build::mainlib)
+add_library(installlib STATIC installlib.c)
+target_link_libraries(installlib PRIVATE install::mainlib)
diff --git a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake
index d07fca2..b730047 100644
--- a/Tests/RunCMake/ExportImport/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExportImport/RunCMakeTest.cmake
@@ -22,3 +22,28 @@ function(run_ExportImport_test case)
endfunction()
run_ExportImport_test(SharedDep)
+
+function(run_ExportImportBuildInstall_test case)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-export-build)
+ set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root)
+ if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+ endif()
+ run_cmake(${case}-export)
+ unset(RunCMake_TEST_OPTIONS)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${case}-export-build ${CMAKE_COMMAND} --build . --config Debug)
+ run_cmake_command(${case}-export-install ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_TYPE=Debug -P cmake_install.cmake)
+ unset(RunCMake_TEST_NO_CLEAN)
+
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-import-build)
+ run_cmake_with_options(${case}-import
+ -Dbuild_DIR=${RunCMake_BINARY_DIR}/${case}-export-build
+ -Dinstall_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/install
+ )
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${case}-import-build ${CMAKE_COMMAND} --build . --config Debug)
+ unset(RunCMake_TEST_NO_CLEAN)
+endfunction()
+
+run_ExportImportBuildInstall_test(BuildInstallInterfaceGenex)
diff --git a/Tests/RunCMake/ExportImport/buildlib.c b/Tests/RunCMake/ExportImport/buildlib.c
new file mode 100644
index 0000000..ac19310
--- /dev/null
+++ b/Tests/RunCMake/ExportImport/buildlib.c
@@ -0,0 +1,8 @@
+#if !(!defined(BUILD_LOCAL_INTERFACE) && defined(BUILD_INTERFACE) && \
+ !defined(INSTALL_INTERFACE))
+# error "Incorrect compile definitions"
+#endif
+
+void buildlib(void)
+{
+}
diff --git a/Tests/RunCMake/ExportImport/installlib.c b/Tests/RunCMake/ExportImport/installlib.c
new file mode 100644
index 0000000..00d503c
--- /dev/null
+++ b/Tests/RunCMake/ExportImport/installlib.c
@@ -0,0 +1,8 @@
+#if !(!defined(BUILD_LOCAL_INTERFACE) && !defined(BUILD_INTERFACE) && \
+ defined(INSTALL_INTERFACE))
+# error "Incorrect compile definitions"
+#endif
+
+void installlib(void)
+{
+}
diff --git a/Tests/RunCMake/ExportImport/locallib.c b/Tests/RunCMake/ExportImport/locallib.c
new file mode 100644
index 0000000..f9e3d8d
--- /dev/null
+++ b/Tests/RunCMake/ExportImport/locallib.c
@@ -0,0 +1,8 @@
+#if !(defined(BUILD_LOCAL_INTERFACE) && defined(BUILD_INTERFACE) && \
+ !defined(INSTALL_INTERFACE))
+# error "Incorrect compile definitions"
+#endif
+
+void locallib(void)
+{
+}
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index 961b73a..c768d18 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -65,6 +65,7 @@ function(run_object object)
endfunction()
run_object(codemodel-v2)
+run_object(configureLog-v1)
run_object(cache-v2)
run_object(cmakeFiles-v1)
run_object(toolchains-v1)
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index b7623de..fda18b5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -12,7 +12,7 @@ def read_codemodel_json_data(filename):
def check_objects(o, g):
assert is_list(o)
assert len(o) == 1
- check_index_object(o[0], "codemodel", 2, 4, check_object_codemodel(g))
+ check_index_object(o[0], "codemodel", 2, 5, check_object_codemodel(g))
def check_backtrace(t, b, backtrace):
btg = t["backtraceGraph"]
@@ -291,10 +291,30 @@ def check_target(c):
assert matches(obj["paths"]["build"], expected["build"])
assert matches(obj["paths"]["source"], expected["source"])
+ def check_file_set(actual, expected):
+ assert is_dict(actual)
+ expected_keys = ["name", "type", "visibility", "baseDirectories"]
+
+ assert is_string(actual["name"], expected["name"])
+ assert is_string(actual["type"], expected["type"])
+ assert is_string(actual["visibility"], expected["visibility"])
+
+ check_list_match(lambda a, e: matches(a, e), actual["baseDirectories"],
+ expected["baseDirectories"],
+ check_exception=lambda a, e: "File set base directory (check): %s" % a,
+ missing_exception=lambda e: "File set base directory (missing): %s" % e,
+ extra_exception=lambda a: "File set base directory (extra): %s" % a)
+
+ assert sorted(actual.keys()) == sorted(expected_keys)
+
def check_source(actual, expected):
assert is_dict(actual)
expected_keys = ["path"]
+ if expected["fileSetName"] is not None:
+ expected_keys.append("fileSetIndex")
+ assert is_string(obj["fileSets"][actual["fileSetIndex"]]["name"], expected["fileSetName"])
+
if expected["compileGroupLanguage"] is not None:
expected_keys.append("compileGroupIndex")
assert is_string(obj["compileGroups"][actual["compileGroupIndex"]]["language"], expected["compileGroupLanguage"])
@@ -313,6 +333,14 @@ def check_target(c):
assert sorted(actual.keys()) == sorted(expected_keys)
+ if expected["fileSets"] is not None:
+ expected_keys.append("fileSets")
+ check_list_match(lambda a, e: matches(a["name"], e["name"]), obj["fileSets"],
+ expected["fileSets"], check=check_file_set,
+ check_exception=lambda a, e: "File set: %s" % a["name"],
+ missing_exception=lambda e: "File set: %s" % e["name"],
+ extra_exception=lambda a: "File set: %s" % a["name"])
+
check_list_match(lambda a, e: matches(a["path"], e["path"]), obj["sources"],
expected["sources"], check=check_source,
check_exception=lambda a, e: "Source file: %s" % a["path"],
@@ -824,6 +852,7 @@ def gen_check_targets(c, g, inSource):
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/CMakeFiles/([0-9a-f]+/)?generate\\.stamp\\.rule$",
"isGenerated": True,
+ "fileSetName": None,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": None,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json
index eabf739..63493c9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_alias.json
@@ -5,10 +5,12 @@
"projectName": "Alias",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/alias/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/alias/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json
index a5ff686..411057c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_custom.json
@@ -5,10 +5,12 @@
"projectName": "Custom",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json
index 1f443b1..bf36bfe 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_cxx.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/cxx/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/cxx/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json
index 017335c..ebda414 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_external.json
@@ -5,10 +5,12 @@
"projectName": "External",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/FileAPIExternalBuild/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/FileAPIExternalBuild/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json
index 2de5b15..579a103 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_imported.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/imported/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/imported/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json
index fa2a6e5..ec03531 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_interface.json
@@ -5,10 +5,12 @@
"projectName": "Interface",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/interface/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/interface/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json
index 9d8899a..f145896 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_object.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json
index 0d45d07..46495ac 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/all_build_top.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/CMakeFiles/ALL_BUILD$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/CMakeFiles/ALL_BUILD\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json
index ac7c94d..a27d328 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_alias_exe.json
@@ -5,10 +5,12 @@
"projectName": "Alias",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
index 7af74c4..7cfc0f2 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_1.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_1.json
index c189623..715514d 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_1.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_1.json
@@ -5,10 +5,37 @@
"projectName": "codemodel-v2",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": [
+ {
+ "name": "HEADERS",
+ "type": "HEADERS",
+ "visibility": "PUBLIC",
+ "baseDirectories": [".*/Tests/RunCMake/FileAPI/fileset$"]
+ },
+ {
+ "name": "a",
+ "type": "HEADERS",
+ "visibility": "PRIVATE",
+ "baseDirectories": [".*/Tests/RunCMake/FileAPI/fileset$"]
+ },
+ {
+ "name": "b",
+ "type": "HEADERS",
+ "visibility": "PUBLIC",
+ "baseDirectories": [".*/Tests/RunCMake/FileAPI/fileset/dir$"]
+ },
+ {
+ "name": "c",
+ "type": "HEADERS",
+ "visibility": "INTERFACE",
+ "baseDirectories": [".*/Tests/RunCMake/FileAPI/fileset$"]
+ }
+ ],
"sources": [
{
"path": "^fileset/empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
@@ -29,6 +56,7 @@
{
"path": "^fileset/error\\.c$",
"isGenerated": null,
+ "fileSetName": "HEADERS",
"sourceGroupName": "Header Files",
"compileGroupLanguage": null,
"backtrace": [
@@ -49,6 +77,7 @@
{
"path": "^fileset/other\\.c$",
"isGenerated": null,
+ "fileSetName": "HEADERS",
"sourceGroupName": "Source Files",
"compileGroupLanguage": null,
"backtrace": [
@@ -69,6 +98,7 @@
{
"path": "^fileset/h1\\.h$",
"isGenerated": null,
+ "fileSetName": "a",
"sourceGroupName": "Header Files",
"compileGroupLanguage": null,
"backtrace": [
@@ -89,6 +119,7 @@
{
"path": "^fileset/dir/h2\\.h$",
"isGenerated": null,
+ "fileSetName": "b",
"sourceGroupName": "Header Files",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_2.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_2.json
index 75fe58c..4757a9c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_2.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_headers_2.json
@@ -5,10 +5,19 @@
"projectName": "codemodel-v2",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": [
+ {
+ "name": "HEADERS",
+ "type": "HEADERS",
+ "visibility": "INTERFACE",
+ "baseDirectories": [".*/Tests/RunCMake/FileAPI/fileset$"]
+ }
+ ],
"sources": [
{
"path": "^fileset/empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
index 0ca1962..2bfc63f 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
index 3392404..6342191 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_exe.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
@@ -29,6 +31,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/c_object_lib\\.build)/.*/empty(\\.c)?\\.o(bj)?$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "Object Libraries",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
index 1917f92..3e1b03b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_object_lib.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "OBJECT_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
index 0d4018a..f7a8db4 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
index 9a210ff..9066053 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "SHARED_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
index 5542277..46c5bfe 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
index 4b63897..df28479 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
index 12ec917..4fa62e3 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^subdir/empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json
index ab301e9..8d52ab8 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_exe.json
@@ -5,10 +5,12 @@
"projectName": "Custom",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json
index 483ae79..23f8e52 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/custom_tgt.json
@@ -5,10 +5,12 @@
"projectName": "Custom",
"type": "UTILITY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/custom_tgt(-(Debug|Release|RelWithDebInfo|MinSizeRel))?$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -29,6 +31,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(custom/)?CMakeFiles/([0-9a-f]+/)?custom_tgt(-\\(CONFIG\\))?\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json
index 837f252..b27fc5b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_alias_exe.json
@@ -5,10 +5,12 @@
"projectName": "Alias",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
index 16d074a..12b2551 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json
index 5a0f770..3251777 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader.json
@@ -97,6 +97,7 @@
{
"path": ".*cmake_pch(_[^.]+)?(\\.hxx)?\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -111,6 +112,7 @@
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -131,6 +133,7 @@
{
"path": ".*/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json
index 9455748..0ac40c2 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_2arch.json
@@ -143,6 +143,7 @@
{
"path": ".*cmake_pch(_[^.]+)?(\\.hxx)?\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -157,6 +158,7 @@
{
"path": ".*cmake_pch(_[^.]+)?(\\.hxx)?\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -171,6 +173,7 @@
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -191,6 +194,7 @@
{
"path": ".*/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
@@ -205,6 +209,7 @@
{
"path": ".*/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json
index 9f6ffcc..86168f1 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_precompileheader_multigen.json
@@ -97,6 +97,7 @@
{
"path": ".*cmake_pch(_[^.]+)?(\\.hxx)?\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -111,6 +112,7 @@
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -131,6 +133,7 @@
{
"path": ".*/Debug/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
@@ -145,6 +148,7 @@
{
"path": ".*/Release/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
@@ -159,6 +163,7 @@
{
"path": ".*/MinSizeRel/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
@@ -173,6 +178,7 @@
{
"path": ".*/RelWithDebInfo/cmake_pch(_[^.]+)?\\.hxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Precompile Header File",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json
index 94ac081..f665004 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_lib.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
index e8d6218..68c5dcc 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_exe.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
@@ -29,6 +31,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/(object|build/cxx_object_lib\\.build)/.*/empty(\\.cxx)?\\.o(bj)?$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "Object Libraries",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
index 24b391b..0438a49 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_object_lib.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "OBJECT_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json
index 4421c8f..bb9989e 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_exe.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
index 03f4cb9..d6d59a4 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "SHARED_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json
index d6d573f..a6bacf7 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json
index 9cb2832..fe884e0 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_exe.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json
index 52c42de..d904bd9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_exe.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json
index 98298be..bced68a 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_static_lib.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "STATIC_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.cxx$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json
index d41bbb2..4b69682 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/generated_exe.json
@@ -5,10 +5,12 @@
"projectName": "External",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPIExternalSource/empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
@@ -29,6 +31,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/FileAPIExternalBuild/generated\\.cxx$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "Generated Source Files",
"compileGroupLanguage": "CXX",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json
index 97d7ccd..bd698d5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/iface_srcs.json
@@ -5,10 +5,12 @@
"projectName": "Interface",
"type": "INTERFACE_LIBRARY",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
index fe0524c..c0c3e79 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json
index 451e8d4..45fb0a5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_exe.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json
index cbd4346..74c179c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_interface_exe.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json
index d92a810..6771747 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_object_exe.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json
index 1197a73..659e3fb 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_shared_exe.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json
index 42564e0..7bdaffb 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/link_imported_static_exe.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "EXECUTABLE",
"isGeneratorProvided": null,
+ "fileSets": null,
"sources": [
{
"path": "^empty\\.c$",
"isGenerated": null,
+ "fileSetName": null,
"sourceGroupName": "Source Files",
"compileGroupLanguage": "C",
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json
index 941c172..7462f7f 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_alias.json
@@ -5,10 +5,12 @@
"projectName": "Alias",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/alias/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/alias/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json
index 98c6dd9..abc5084 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_custom.json
@@ -5,10 +5,12 @@
"projectName": "Custom",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/custom/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json
index b72ff82..af4248c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_cxx.json
@@ -5,10 +5,12 @@
"projectName": "Cxx",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/cxx/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/cxx/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json
index 9e73806..a7b8bb0 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_external.json
@@ -5,10 +5,12 @@
"projectName": "External",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/FileAPIExternalBuild/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/FileAPIExternalBuild/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json
index 7534c84..ed3da5f 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_imported.json
@@ -5,10 +5,12 @@
"projectName": "Imported",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/imported/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/imported/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json
index fdd4b2a..178f9ef 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_interface.json
@@ -5,10 +5,12 @@
"projectName": "Interface",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/interface/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/interface/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json
index bcd7616..341647b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_object.json
@@ -5,10 +5,12 @@
"projectName": "Object",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/object/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json
index b3030bd..b3827ed 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/zero_check_top.json
@@ -5,10 +5,12 @@
"projectName": "codemodel-v2",
"type": "UTILITY",
"isGeneratorProvided": true,
+ "fileSets": null,
"sources": [
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/CMakeFiles/ZERO_CHECK$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "",
"compileGroupLanguage": null,
"backtrace": [
@@ -23,6 +25,7 @@
{
"path": "^.*/Tests/RunCMake/FileAPI/codemodel-v2-build/CMakeFiles/ZERO_CHECK\\.rule$",
"isGenerated": true,
+ "fileSetName": null,
"sourceGroupName": "CMake Rules",
"compileGroupLanguage": null,
"backtrace": [
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake
new file mode 100644
index 0000000..bd4081c
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+ query
+ query/client-foo
+ query/client-foo/query.json
+ reply
+ reply/configureLog-v1-[0-9a-f]+.json
+ reply/index-[0-9.T-]+.json
+ )
+check_api("^${expect}$")
+
+check_python(configureLog-v1)
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-prep.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-prep.cmake
new file mode 100644
index 0000000..c443487
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-prep.cmake
@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+ { "requests": [ { "kind": "configureLog", "version" : 1 } ] }
+]])
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-check.cmake
new file mode 100644
index 0000000..7498dd5
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-check.cmake
@@ -0,0 +1,11 @@
+set(expect
+ query
+ query/client-foo
+ query/client-foo/configureLog-v1
+ reply
+ reply/configureLog-v1-[0-9a-f]+.json
+ reply/index-[0-9.T-]+.json
+ )
+check_api("^${expect}$")
+
+check_python(configureLog-v1)
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-prep.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-prep.cmake
new file mode 100644
index 0000000..ad49e08
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/configureLog-v1" "")
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-check.cmake
new file mode 100644
index 0000000..3e34be6
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-check.cmake
@@ -0,0 +1,10 @@
+set(expect
+ query
+ query/configureLog-v1
+ reply
+ reply/configureLog-v1-[0-9a-f]+.json
+ reply/index-[0-9.T-]+.json
+ )
+check_api("^${expect}$")
+
+check_python(configureLog-v1)
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-prep.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-prep.cmake
new file mode 100644
index 0000000..6fe0037
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-SharedStateless-prep.cmake
@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/configureLog-v1" "")
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-check.py b/Tests/RunCMake/FileAPI/configureLog-v1-check.py
new file mode 100644
index 0000000..05c7893
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-check.py
@@ -0,0 +1,21 @@
+from check_index import *
+import os
+
+def check_objects(o):
+ assert is_list(o)
+ assert len(o) == 1
+ check_index_object(o[0], "configureLog", 1, 0, check_object_configureLog)
+
+def check_object_configureLog(o):
+ assert sorted(o.keys()) == ["eventKindNames", "kind", "path", "version"]
+ # The "kind" and "version" members are handled by check_index_object.
+ path = o["path"]
+ assert matches(path, "^.*/CMakeFiles/CMakeConfigureLog\\.yaml$")
+ assert os.path.exists(path)
+ eventKindNames = o["eventKindNames"]
+ assert is_list(eventKindNames)
+ assert sorted(eventKindNames) == ["message-v1", "try_compile-v1", "try_run-v1"]
+
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1.cmake b/Tests/RunCMake/FileAPI/configureLog-v1.cmake
new file mode 100644
index 0000000..c00af08
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/configureLog-v1.cmake
@@ -0,0 +1 @@
+enable_language(C)
diff --git a/Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt b/Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt
index d7bc79a..c2d4071 100644
--- a/Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt
+++ b/Tests/RunCMake/File_Archive/argument-validation-compression-level-1-stderr.txt
@@ -1,5 +1,5 @@
CMake Error at compression-level.cmake:39 \(file\):
- file compression level 100 should be in range 0 to 9
+ file compression level 100 for GZip should be in range 0 to 9
Call Stack \(most recent call first\):
argument-validation-compression-level-1.cmake:8 \(check_compression_level\)
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt b/Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt
index 0f7bd9e..d4a4402 100644
--- a/Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt
+++ b/Tests/RunCMake/File_Archive/argument-validation-compression-level-2-stderr.txt
@@ -1,5 +1,5 @@
CMake Error at compression-level.cmake:39 \(file\):
- file compression level high should be in range 0 to 9
+ file compression level high for GZip should be in range 0 to 9
Call Stack \(most recent call first\):
argument-validation-compression-level-2.cmake:8 \(check_compression_level\)
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake b/Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake
index 73fd84d..7002860 100644
--- a/Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake
+++ b/Tests/RunCMake/File_Archive/pax-zstd-compression-level.cmake
@@ -8,3 +8,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/compression-level.cmake)
check_compression_level("1")
check_compression_level("5")
check_compression_level("9")
+check_compression_level("12")
+check_compression_level("15")
+check_compression_level("19")
diff --git a/Tests/RunCMake/FindBoost/CommonNotFound.cmake b/Tests/RunCMake/FindBoost/CommonNotFound.cmake
index 864a549..b146d3d 100644
--- a/Tests/RunCMake/FindBoost/CommonNotFound.cmake
+++ b/Tests/RunCMake/FindBoost/CommonNotFound.cmake
@@ -1,2 +1,6 @@
+set(CMAKE_FIND_USE_CMAKE_PATH OFF)
+set(CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH OFF)
+set(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH OFF)
+set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
# Make sure to use the module mode signature here to not bypass FindBoost
find_package(Boost 1.80 COMPONENTS timer foobar)
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
index f149d99..69ab4da 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_IMPORTED_TARGET.cmake
@@ -113,23 +113,33 @@ message(STATUS "Verifying target \"${tgt}\"")
if (NOT TARGET ${tgt})
message(FATAL_ERROR "No import target for fake link options package")
endif()
-get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS)
-if (NOT link_options STREQUAL expected_link_options)
- message(FATAL_ERROR
- "Additional link options not present in INTERFACE_LINK_OPTIONS property\n"
- "expected: \"${expected_link_options}\", but got \"${link_options}\""
- )
-endif()
-get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES)
-set(expected_inc_dirs "/special" "/other" "/more")
+# Some versions of pkg-config on Windows don't parse the Libs and Cflags
+# correctly. The pkg-config that comes with Strawberry perl is one example.
+# It appears to treat the dummymain part of Libs as a library and only returns
+# -e. It also doesn't recognize "-isystem /other", presumably because it doesn't
+# support having a space between "-isystem" and the directory after it (it does
+# give us the "-isystem/more" flag). Since we can't reliably test for these,
+# we don't enable these checks on Windows.
+if(NOT WIN32)
+ get_target_property(link_options ${tgt} INTERFACE_LINK_OPTIONS)
+ if (NOT link_options STREQUAL expected_link_options)
+ message(FATAL_ERROR
+ "Additional link options not present in INTERFACE_LINK_OPTIONS property\n"
+ "expected: \"${expected_link_options}\", but got \"${link_options}\""
+ )
+ endif()
-if (NOT inc_dirs STREQUAL expected_inc_dirs)
- message(FATAL_ERROR
- "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n"
- "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\""
- )
-endif ()
+ get_target_property(inc_dirs ${tgt} INTERFACE_INCLUDE_DIRECTORIES)
+ set(expected_inc_dirs "/special" "/other" "/more")
+
+ if (NOT inc_dirs STREQUAL expected_inc_dirs)
+ message(FATAL_ERROR
+ "Additional include directories not correctly present in INTERFACE_INCLUDE_DIRECTORIES property\n"
+ "expected: \"${expected_inc_dirs}\", got \"${inc_dirs}\""
+ )
+ endif ()
+endif()
get_target_property(c_opts ${tgt} INTERFACE_COMPILE_OPTIONS)
set(expected_c_opts "-DA-isystem/foo") # this is an invalid option, but a good testcase
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
index 2a505c6..f7a9815 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_VERSION_OPERATORS.cmake
@@ -20,14 +20,15 @@ Libs: -lcmakeinternalfakepackage
# Always find the .pc file in the calls further below so that we can test that
# the import target find_library() calls handle the NO...PATH options correctly
-set(ENV{PKG_CONFIG_PATH} ${fakePkgDir}/lib/pkgconfig)
+cmake_path(CONVERT "${fakePkgDir}/lib/pkgconfig" TO_NATIVE_PATH_LIST confPath)
+set(ENV{PKG_CONFIG_PATH} "${confPath}")
-pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage >= 8")
+pkg_check_modules(FakePackageGE REQUIRED QUIET "cmakeinternalfakepackage>=8")
if (NOT FakePackageGE_FOUND)
message(FATAL_ERROR "fake package >= 8 not found")
endif()
-pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage >= 8.10")
+pkg_check_modules(FakePackageGE_FAIL QUIET "cmakeinternalfakepackage>=8.10")
if (FakePackageGE_FAIL_FOUND)
message(FATAL_ERROR "fake package >= 8.10 found")
endif()
@@ -37,17 +38,17 @@ if (NOT FakePackageLE_FOUND)
message(FATAL_ERROR "fake package <= 9 not found")
endif()
-pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage <= 8.1")
+pkg_check_modules(FakePackageLE_FAIL QUIET "cmakeinternalfakepackage<=8.1")
if (FakePackageLE_FAIL_FOUND)
message(FATAL_ERROR "fake package <= 8.1 found")
endif()
-pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage > 8")
+pkg_check_modules(FakePackageGT REQUIRED QUIET "cmakeinternalfakepackage>8")
if (NOT FakePackageGT_FOUND)
message(FATAL_ERROR "fake package > 8 not found")
endif()
-pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage > 8.9")
+pkg_check_modules(FakePackageGT_FAIL QUIET "cmakeinternalfakepackage>8.9")
if (FakePackageGT_FAIL_FOUND)
message(FATAL_ERROR "fake package > 8.9 found")
endif()
@@ -57,7 +58,7 @@ if (NOT FakePackageLT_FOUND)
message(FATAL_ERROR "fake package < 9 not found")
endif()
-pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage < 8.9")
+pkg_check_modules(FakePackageLT_FAIL QUIET "cmakeinternalfakepackage<8.9")
if (FakePackageLT_FAIL_FOUND)
message(FATAL_ERROR "fake package < 8.9 found")
endif()
@@ -67,17 +68,17 @@ if (NOT FakePackageEQ_FOUND)
message(FATAL_ERROR "fake package = 8.9 not found")
endif()
-pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage = 8.8")
+pkg_check_modules(FakePackageEQ_FAIL QUIET "cmakeinternalfakepackage=8.8")
if (FakePackageEQ_FAIL_FOUND)
message(FATAL_ERROR "fake package = 8.8 found")
endif()
-pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage == 8.9")
+pkg_check_modules(FakePackageEQ_INV QUIET "cmakeinternalfakepackage==8.9")
if (FakePackageEQ_FAIL_FOUND)
message(FATAL_ERROR "fake package == 8.9 found")
endif()
-pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage <<= 9")
+pkg_check_modules(FakePackageLLT_INV QUIET "cmakeinternalfakepackage<<=9")
if (FakePackageLLT_FAIL_FOUND)
message(FATAL_ERROR "fake package <<= 9 found")
endif()
diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
index 661ae3f..6b8e884 100644
--- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
@@ -7,13 +7,18 @@ set(ENV{CMAKE_FRAMEWORK_PATH} "")
run_cmake(PkgConfigDoesNotExist)
-run_cmake(FindPkgConfig_CMP0126_NEW)
-run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH)
-run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH)
+if(NOT WIN32)
+ # FIXME: The Windows implementation of these tests do not work.
+ # They are disabled until they can be updated to a working state.
+ run_cmake(FindPkgConfig_CMP0126_NEW)
+ run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH)
+ run_cmake(FindPkgConfig_PKGCONFIG_PATH)
+ run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH)
+ run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_ENVIRONMENT_PATH)
+ run_cmake(FindPkgConfig_GET_MATCHING_ARGN)
+endif()
+
run_cmake(FindPkgConfig_extract_frameworks)
-run_cmake(FindPkgConfig_GET_MATCHING_ARGN)
if(APPLE)
run_cmake(FindPkgConfig_extract_frameworks_target)
diff --git a/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt b/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt
index 013c4f2..9af0573 100644
--- a/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_FILE/OUTPUT_NAME-recursion-stderr.txt
@@ -1,5 +1,5 @@
CMake Error at OUTPUT_NAME-recursion.cmake:[0-9]+ \(add_executable\):
- Target 'empty2' OUTPUT_NAME depends on itself.
+ Target 'empty1' OUTPUT_NAME depends on itself.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL-check.cmake
index 0fbf837..0fbf837 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL-check.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL-check.cmake
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL.cmake
index 212c034..212c034 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-ALIAS_GLOBAL.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/ALIAS_GLOBAL.cmake
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-stderr.txt
index 6da79b7..6da79b7 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName.cmake
index 5f083e2..d3f82aa 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName.cmake
@@ -1,3 +1,4 @@
+enable_language(CXX)
add_subdirectory(BadInvalidName1)
add_subdirectory(BadInvalidName2)
add_subdirectory(BadInvalidName3)
@@ -6,3 +7,6 @@ add_subdirectory(BadInvalidName5)
add_subdirectory(BadInvalidName6)
add_subdirectory(BadInvalidName7)
add_subdirectory(BadInvalidName8)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName1/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName1/CMakeLists.txt
index 13e1de7..13e1de7 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName1/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName1/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName2/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName2/CMakeLists.txt
index 4b78472..4b78472 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName2/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName2/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName3/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName3/CMakeLists.txt
index 516a049..516a049 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName3/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName3/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName4/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName4/CMakeLists.txt
index 02f2a1a..02f2a1a 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName4/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName4/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName5/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName5/CMakeLists.txt
index a653583..a653583 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName5/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName5/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName6/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName6/CMakeLists.txt
index 614458e..614458e 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName6/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName6/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName7/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName7/CMakeLists.txt
index 8a9fe80..8a9fe80 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName7/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName7/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName8/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName8/CMakeLists.txt
index b228159..b228159 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadInvalidName8/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadInvalidName8/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-stderr.txt
index d40b16b..0c9320b 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at BadNonTarget.cmake:7 \(include_directories\):
+CMake Error at BadNonTarget.cmake:6 \(include_directories\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:NonExistent,INCLUDE_DIRECTORIES>
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget.cmake
new file mode 100644
index 0000000..731d758
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadNonTarget.cmake
@@ -0,0 +1,9 @@
+enable_language(CXX)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+ "int main(int, char **) { return 0; }\n")
+
+add_executable(main "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+include_directories("$<TARGET_PROPERTY:NonExistent,INCLUDE_DIRECTORIES>")
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-stderr.txt
index fa26861..fa26861 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference.cmake
index 5a99f7a..ee8b9ec 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference.cmake
@@ -1,6 +1,10 @@
+enable_language(CXX)
add_subdirectory(BadSelfReference1)
add_subdirectory(BadSelfReference2)
add_subdirectory(BadSelfReference3)
add_subdirectory(BadSelfReference4)
add_subdirectory(BadSelfReference5)
add_subdirectory(BadSelfReference6)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference1/CMakeLists.txt
index 30c27f5..30c27f5 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference1/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference1/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference2/CMakeLists.txt
index c2322f4..c2322f4 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference2/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference2/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference3/CMakeLists.txt
index 3e6c30a..3e6c30a 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference3/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference3/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference4/CMakeLists.txt
index f79727a..f79727a 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference4/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference4/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference5/CMakeLists.txt
index c0badbf..c0badbf 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference5/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference5/CMakeLists.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference6/CMakeLists.txt
index fcb6b3c..fcb6b3c 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadSelfReference6/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/BadSelfReference6/CMakeLists.txt
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
new file mode 100644
index 0000000..26a73f9
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.3)
+if(RunCMake_TEST STREQUAL "LOCATION")
+ cmake_minimum_required(VERSION 2.8.12) # Leave CMP0026 unset.
+endif()
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES-check.cmake
index ecf7bfe..ecf7bfe 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES-check.cmake
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES.cmake
index e9855be..e9855be 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/INCLUDE_DIRECTORIES.cmake
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION-stderr.txt
index a4c8dcd..a4c8dcd 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION-stderr.txt
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION.cmake
index 8929cdb..8929cdb 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-LOCATION.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LOCATION.cmake
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-stderr.txt
index 8bff68e..8bff68e 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1.cmake
index 4b60214..775e5a0 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle1.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle1.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
@@ -6,3 +6,6 @@ target_link_libraries(empty1
LINK_PUBLIC
$<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-stderr.txt
index 044b77c..044b77c 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2.cmake
index 557eac1..fc14b48 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle2.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle2.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
@@ -6,3 +6,6 @@ target_link_libraries(empty1
LINK_PUBLIC
$<$<STREQUAL:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3-result.txt
index 573541a..573541a 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3.cmake
index 0f921d4..e084502 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle3.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle3.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
@@ -8,3 +8,6 @@ target_link_libraries(empty1
INTERFACE
$<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-stderr.txt
index d56b199..d56b199 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4.cmake
index ab6d0b2..42290de 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle4.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle4.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
@@ -12,3 +12,6 @@ target_link_libraries(empty1
add_library(empty3 empty.cpp)
target_link_libraries(empty3 empty1)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-stderr.txt
index cf4e6d7..cf4e6d7 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5.cmake
index dc180e3..9597176 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle5.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle5.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 INTERFACE IMPORTED)
add_library(empty2 INTERFACE IMPORTED)
@@ -8,3 +8,6 @@ set_property(TARGET empty1 PROPERTY INTERFACE_LINK_LIBRARIES
add_library(empty3 empty.cpp)
target_link_libraries(empty3 empty1)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-result.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-result.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-result.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-stderr.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-stderr.txt
index 93cb573..93cb573 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6-stderr.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6-stderr.txt
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6.cmake
index 91252d0..94a5419 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/LinkImplementationCycle6.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/LinkImplementationCycle6.cmake
@@ -1,4 +1,4 @@
-
+enable_language(CXX)
add_library(empty1 SHARED empty.cpp)
add_library(empty2 SHARED empty.cpp)
@@ -12,3 +12,6 @@ target_link_libraries(empty1
add_library(empty3 SHARED empty.cpp)
target_link_libraries(empty3 empty1)
+
+# Suppress generator-specific targets that might pollute the stderr.
+set(CMAKE_SUPPRESS_REGENERATION TRUE)
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
index 4294e9f..b613ad1 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
@@ -1,11 +1,22 @@
include(RunCMake)
-run_cmake(BadSelfReference)
-run_cmake(BadNonTarget)
+run_cmake(ALIAS_GLOBAL)
run_cmake(BadInvalidName)
+run_cmake(BadNonTarget)
+run_cmake(BadSelfReference)
+run_cmake(INCLUDE_DIRECTORIES)
run_cmake(LinkImplementationCycle1)
run_cmake(LinkImplementationCycle2)
run_cmake(LinkImplementationCycle3)
run_cmake(LinkImplementationCycle4)
run_cmake(LinkImplementationCycle5)
run_cmake(LinkImplementationCycle6)
+run_cmake(LOCATION)
+run_cmake(SOURCES)
+
+block()
+ run_cmake(Scope)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Scope-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(Scope-build ${CMAKE_COMMAND} --build . --config Debug)
+endblock()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES-check.cmake
index c1a0f5b..c1a0f5b 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES-check.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES-check.cmake
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES.cmake
index dee7ead..dee7ead 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-SOURCES.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/SOURCES.cmake
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt
new file mode 100644
index 0000000..fefad22
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope-build-stdout.txt
@@ -0,0 +1,6 @@
+.*iface scope1: 'SCOPED_A_1;SCOPED_B_1'
+.*iface scope2: 'SCOPED_A_2'
+.*iface scope2 in scope1: 'SCOPED_A_2'
+.*custom scope1: 'SCOPED_A_1;SCOPED_B_1'
+.*custom scope2: 'SCOPED_A_2'
+.*custom scope2 in scope1: 'SCOPED_A_1'
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c
new file mode 100644
index 0000000..a4bec6f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.c
@@ -0,0 +1,12 @@
+#ifndef SCOPED_A_1
+# error "SCOPED_A_1 not defined"
+#endif
+#ifndef SCOPED_B_1
+# error "SCOPED_B_1 not defined"
+#endif
+#ifndef SCOPED_A_2
+# error "SCOPED_A_2 not defined"
+#endif
+void Scope(void)
+{
+}
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake
new file mode 100644
index 0000000..48a878a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope.cmake
@@ -0,0 +1,19 @@
+enable_language(C)
+
+add_subdirectory(Scope1)
+add_subdirectory(Scope2)
+
+add_library(Scope Scope.c)
+target_link_libraries(Scope PRIVATE
+ scope1_iface
+ scope2_iface
+ )
+
+add_custom_target(Custom ALL VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E echo "iface scope1: '$<TARGET_PROPERTY:scope1_iface,INTERFACE_COMPILE_DEFINITIONS>'"
+ COMMAND ${CMAKE_COMMAND} -E echo "iface scope2: '$<TARGET_PROPERTY:scope2_iface,INTERFACE_COMPILE_DEFINITIONS>'"
+ COMMAND ${CMAKE_COMMAND} -E echo "iface scope2 in scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope2_iface,INTERFACE_COMPILE_DEFINITIONS>>'"
+ COMMAND ${CMAKE_COMMAND} -E echo "custom scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope1_iface,CUSTOM_PROP>>'"
+ COMMAND ${CMAKE_COMMAND} -E echo "custom scope2: '$<TARGET_GENEX_EVAL:scope2_iface,$<TARGET_PROPERTY:scope2_iface,CUSTOM_PROP>>'"
+ COMMAND ${CMAKE_COMMAND} -E echo "custom scope2 in scope1: '$<TARGET_GENEX_EVAL:scope1_iface,$<TARGET_PROPERTY:scope2_iface,CUSTOM_PROP>>'"
+ )
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt
new file mode 100644
index 0000000..d546267
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope1/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_library(scopedA INTERFACE IMPORTED)
+set_property(TARGET scopedA PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_A_1")
+
+add_library(scopedB INTERFACE IMPORTED)
+set_property(TARGET scopedB PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_B_1")
+
+add_library(scope1_iface INTERFACE)
+set_property(TARGET scope1_iface PROPERTY INTERFACE_COMPILE_DEFINITIONS
+ "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>"
+ "$<TARGET_PROPERTY:scopedB,INTERFACE_COMPILE_DEFINITIONS>"
+ )
+set_property(TARGET scope1_iface PROPERTY CUSTOM_PROP
+ "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>"
+ "$<TARGET_PROPERTY:scopedB,INTERFACE_COMPILE_DEFINITIONS>"
+ )
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt
new file mode 100644
index 0000000..a6d7e6b
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/Scope2/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_library(scopedA INTERFACE IMPORTED)
+set_property(TARGET scopedA PROPERTY INTERFACE_COMPILE_DEFINITIONS "SCOPED_A_2")
+
+add_library(scope2_iface INTERFACE)
+set_property(TARGET scope2_iface PROPERTY INTERFACE_COMPILE_DEFINITIONS
+ "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>"
+ )
+set_property(TARGET scope2_iface PROPERTY CUSTOM_PROP
+ "$<TARGET_PROPERTY:scopedA,INTERFACE_COMPILE_DEFINITIONS>"
+ )
diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.c
index e69de29..e69de29 100644
--- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.c
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/empty.cpp b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.cpp
index 11ec041..11ec041 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/empty.cpp
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.cpp
diff --git a/Tests/RunCMake/GeneratorExpression/empty2.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.c
index e69de29..e69de29 100644
--- a/Tests/RunCMake/GeneratorExpression/empty2.c
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.c
diff --git a/Tests/RunCMake/GeneratorExpression/empty3.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.c
index e69de29..e69de29 100644
--- a/Tests/RunCMake/GeneratorExpression/empty3.c
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.c
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/main.cpp b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.cpp
index f8b643a..f8b643a 100644
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/main.cpp
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.cpp
diff --git a/Tests/RunCMake/GenerateExportHeader/reference/.gitattributes b/Tests/RunCMake/GenerateExportHeader/reference/.gitattributes
index d9b566e..883a7f1 100644
--- a/Tests/RunCMake/GenerateExportHeader/reference/.gitattributes
+++ b/Tests/RunCMake/GenerateExportHeader/reference/.gitattributes
@@ -1,2 +1,2 @@
# Exclude reference content from formatting.
-* -format.clang-format-6.0
+* -format.clang-format
diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
index 130de2b..b61ccd2 100644
--- a/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG-stderr.txt
@@ -25,4 +25,13 @@ CMake Error at BadCONFIG.cmake:1 \(add_custom_target\):
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
+
+CMake Warning at BadCONFIG.cmake:1 \(add_custom_target\):
+ Warning evaluating generator expression:
+
+ \$<CONFIG:Release,Foo-Second>
+
+ The config name of "Foo-Second" is invalid
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
++
CMake Generate step failed\. Build files cannot be regenerated correctly\.$
diff --git a/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake b/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake
index 1735ab7..4d7a357 100644
--- a/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake
+++ b/Tests/RunCMake/GeneratorExpression/BadCONFIG.cmake
@@ -2,4 +2,5 @@ add_custom_target(check ALL COMMAND check
$<CONFIG:.>
$<CONFIG:Foo-Bar>
$<$<CONFIG:Foo-Nested>:foo>
+ $<$<CONFIG:Release,Foo-Second>:foo>
VERBATIM)
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index edeb6bd..2d545d9 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -12,7 +12,6 @@ run_cmake(BadTargetTypeInterface)
run_cmake(BadTargetTypeObject)
run_cmake(BadInstallPrefix)
run_cmake(BadSHELL_PATH)
-run_cmake(BadCONFIG)
run_cmake(CMP0044-WARN)
run_cmake(NonValidTarget-C_COMPILER_ID)
run_cmake(NonValidTarget-CXX_COMPILER_ID)
@@ -22,10 +21,6 @@ run_cmake(NonValidTarget-CXX_COMPILER_VERSION)
run_cmake(NonValidTarget-Fortran_COMPILER_VERSION)
run_cmake(NonValidTarget-TARGET_PROPERTY)
run_cmake(NonValidTarget-TARGET_POLICY)
-run_cmake(TARGET_PROPERTY-INCLUDE_DIRECTORIES)
-run_cmake(TARGET_PROPERTY-LOCATION)
-run_cmake(TARGET_PROPERTY-SOURCES)
-run_cmake(TARGET_PROPERTY-ALIAS_GLOBAL)
run_cmake(LINK_ONLY-not-linking)
run_cmake(TARGET_EXISTS-no-arg)
run_cmake(TARGET_EXISTS-empty-arg)
diff --git a/Tests/RunCMake/GeneratorInstance/DefaultInstance-stdout.txt b/Tests/RunCMake/GeneratorInstance/DefaultInstance-stdout.txt
new file mode 100644
index 0000000..078d96e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorInstance/DefaultInstance-stdout.txt
@@ -0,0 +1 @@
+-- CMAKE_VS_VERSION_BUILD_NUMBER='[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
diff --git a/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake
index 9761f0c..5c5ec56 100644
--- a/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake
+++ b/Tests/RunCMake/GeneratorInstance/DefaultInstance.cmake
@@ -12,3 +12,5 @@ elseif(NOT IS_DIRECTORY "${CMAKE_GENERATOR_INSTANCE}")
"which is not an existing directory.")
endif()
file(WRITE "${CMAKE_BINARY_DIR}/instance.txt" "${CMAKE_GENERATOR_INSTANCE}")
+
+message(STATUS "CMAKE_VS_VERSION_BUILD_NUMBER='${CMAKE_VS_VERSION_BUILD_NUMBER}'")
diff --git a/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake b/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
index d1bc9b1..9cc05d0 100644
--- a/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
+++ b/Tests/RunCMake/GetPrerequisites/ExecutableScripts.cmake
@@ -10,7 +10,9 @@ endfunction()
# Should not throw any errors
# Regular executable
-get_prerequisites(${CMAKE_COMMAND} cmake_prereqs 1 1 "" "")
+if(SAMPLE_EXE)
+ get_prerequisites("${SAMPLE_EXE}" cmake_prereqs 1 1 "" "")
+endif()
# Shell script
check_script(${CMAKE_CURRENT_LIST_DIR}/script.sh)
# Batch script
diff --git a/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake b/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
index a635e38..5550c02 100644
--- a/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GetPrerequisites/RunCMakeTest.cmake
@@ -1,4 +1,4 @@
include(RunCMake)
run_cmake_command(TargetMissing ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/TargetMissing.cmake)
-run_cmake_command(ExecutableScripts ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ExecutableScripts.cmake)
+run_cmake_command(ExecutableScripts ${CMAKE_COMMAND} -DSAMPLE_EXE=${SAMPLE_EXE} -P ${RunCMake_SOURCE_DIR}/ExecutableScripts.cmake)
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt
index 8d7527c..18f133a 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-skip-test-stdout.txt
@@ -1,10 +1,13 @@
Test project .*
*Start +[0-9]+: skip_test\.test1
*[0-9]+/[0-9]+ +Test +#[0-9]+: skip_test\.test1 \.+\*\*\*Skipped +[0-9.]+ sec
+ *Start +[0-9]+: skip_test\.test1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: skip_test\.test1 \.+\*\*\*Skipped +[0-9.]+ sec
-100% tests passed, 0 tests failed out of 1
+100% tests passed, 0 tests failed out of 2
Total Test time \(real\) = +[0-9.]+ sec
The following tests did not run:
[ 0-9]+- skip_test\.test1 \(Skipped\)
+[ 0-9]+- skip_test\.test1 \(Skipped\)
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest.cmake b/Tests/RunCMake/GoogleTest/GoogleTest.cmake
index 221d6ad..2ed43fc 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest.cmake
+++ b/Tests/RunCMake/GoogleTest/GoogleTest.cmake
@@ -78,3 +78,7 @@ xcode_sign_adhoc(skip_test)
gtest_discover_tests(
skip_test
)
+
+gtest_add_tests(
+ TARGET skip_test
+)
diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
index 695f562..b494cef 100644
--- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
@@ -1,5 +1,9 @@
include(RunCMake)
+# Isolate our ctest runs from external environment.
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+
if(RunCMake_GENERATOR STREQUAL "Borland Makefiles" OR
RunCMake_GENERATOR STREQUAL "Watcom WMake")
set(fs_delay 3)
diff --git a/Tests/RunCMake/GoogleTest/skip_test.cpp b/Tests/RunCMake/GoogleTest/skip_test.cpp
index 2bc9fe1..919b1b3 100644
--- a/Tests/RunCMake/GoogleTest/skip_test.cpp
+++ b/Tests/RunCMake/GoogleTest/skip_test.cpp
@@ -1,6 +1,13 @@
#include <iostream>
#include <string>
+/* Having this as comment lets gtest_add_tests recognizes the test we fake
+ here without requiring googletest
+TEST_F( skip_test, test1 )
+{
+}
+*/
+
int main(int argc, char** argv)
{
// Note: GoogleTest.cmake doesn't actually depend on Google Test as such;
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index b94466c..9214e90 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -46,8 +46,17 @@ if(WIN32)
if(RunCMake_MAKE_PROGRAM)
set(maybe_MAKE_PROGRAM "-DRunCMake_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
endif()
- run_cmake_script(ShowIncludes-54936 -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
- run_cmake_script(ShowIncludes-65001 -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-437-English -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-437-French -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-437-German -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-437-Italian -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-54936-Chinese -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-65001-Chinese -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-65001-French -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ run_cmake_script(ShowIncludes-65001-Japanese -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ if(NOT CMake_TEST_NO_CODEPAGE_9xx)
+ run_cmake_script(ShowIncludes-932-Japanese -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM})
+ endif()
unset(maybe_MAKE_PROGRAM)
endif()
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-English-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-English-check.cmake
new file mode 100644
index 0000000..9338709
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-English-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1033' and 'chcp 437'.
+set(expect "Note: including file: ")
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-English-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-437-English-stdout.txt
new file mode 100644
index 0000000..bda7eab
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-English-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='Note: including file: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-English.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-English.cmake
new file mode 100644
index 0000000..194b637
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-English.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 437)
+set(VSLANG 1033)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-French-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-French-check.cmake
new file mode 100644
index 0000000..64b0498
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-French-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1036' and 'chcp 437'.
+string(ASCII 82 101 109 97 114 113 117 101 255 58 32 105 110 99 108 117 115 105 111 110 32 100 117 32 102 105 99 104 105 101 114 255 58 32 32 expect)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-French-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-437-French-stdout.txt
new file mode 100644
index 0000000..1a830f1
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-French-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='Remarque : inclusion du fichier : '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-French.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-French.cmake
new file mode 100644
index 0000000..9fe4055
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-French.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 437)
+set(VSLANG 1036)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-German-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-German-check.cmake
new file mode 100644
index 0000000..c1418e3
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-German-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1031' and 'chcp 437'.
+set(expect "Hinweis: Einlesen der Datei: ")
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-German-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-437-German-stdout.txt
new file mode 100644
index 0000000..9b9875e
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-German-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='Hinweis: Einlesen der Datei: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-German.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-German.cmake
new file mode 100644
index 0000000..882a23c
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-German.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 437)
+set(VSLANG 1031)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-check.cmake
new file mode 100644
index 0000000..014ce7f
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1040' and 'chcp 437'.
+set(expect "Nota: file incluso ")
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-stdout.txt
new file mode 100644
index 0000000..9dd03a5
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='Nota: file incluso '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-Italian.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian.cmake
new file mode 100644
index 0000000..be04271
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-437-Italian.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 437)
+set(VSLANG 1040)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-54936-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-check.cmake
index 40bb68f..c5744b7 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes-54936-check.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-check.cmake
@@ -1,3 +1,3 @@
# 'cl /showIncludes' prefix with 'VSLANG=2052' and 'chcp 54936'.
-string(ASCII 215 162 210 226 58 32 176 252 186 172 206 196 188 254 58 expect)
+string(ASCII 215 162 210 226 58 32 176 252 186 172 206 196 188 254 58 32 32 expect)
include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-stdout.txt
new file mode 100644
index 0000000..b9ac962
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='注意: 包含文件: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-54936.cmake b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese.cmake
index 07b4192..77a4014 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes-54936.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes-54936-Chinese.cmake
@@ -1,2 +1,3 @@
set(CODEPAGE 54936)
+set(VSLANG 2052)
include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-54936-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-54936-stdout.txt
deleted file mode 100644
index 42a2f35..0000000
--- a/Tests/RunCMake/Ninja/ShowIncludes-54936-stdout.txt
+++ /dev/null
@@ -1 +0,0 @@
--- showIncludes='注意: 包含文件:'
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-check.cmake
index c73b734..6f61d3c 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes-65001-check.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-check.cmake
@@ -1,3 +1,3 @@
# 'cl /showIncludes' prefix with 'VSLANG=2052' and 'chcp 65001'.
-string(ASCII 230 179 168 230 132 143 58 32 229 140 133 229 144 171 230 150 135 228 187 182 58 expect)
+string(ASCII 230 179 168 230 132 143 58 32 229 140 133 229 144 171 230 150 135 228 187 182 58 32 32 expect)
include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-stdout.txt
new file mode 100644
index 0000000..b9ac962
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='注意: 包含文件: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese.cmake
index 0eebd61..0e61c4a 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes-65001.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Chinese.cmake
@@ -1,2 +1,3 @@
set(CODEPAGE 65001)
+set(VSLANG 2052)
include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-French-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-French-check.cmake
new file mode 100644
index 0000000..133cbe6
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-French-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1036' and 'chcp 65001'.
+string(ASCII 82 101 109 97 114 113 117 101 194 160 58 32 105 110 99 108 117 115 105 111 110 32 100 117 32 102 105 99 104 105 101 114 194 160 58 32 32 expect)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-French-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-65001-French-stdout.txt
new file mode 100644
index 0000000..1a830f1
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-French-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='Remarque : inclusion du fichier : '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-French.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-French.cmake
new file mode 100644
index 0000000..49927f6
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-French.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 65001)
+set(VSLANG 1036)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-check.cmake
new file mode 100644
index 0000000..852bae7
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1041' and 'chcp 65001'.
+string(ASCII 227 131 161 227 131 162 58 32 227 130 164 227 131 179 227 130 175 227 131 171 227 131 188 227 131 137 32 227 131 149 227 130 161 227 130 164 227 131 171 58 32 32 expect)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-stdout.txt
new file mode 100644
index 0000000..4640616
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='メモ: インクルード ファイル: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese.cmake b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese.cmake
new file mode 100644
index 0000000..59cc84e
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-65001-Japanese.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 65001)
+set(VSLANG 1041)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-65001-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-65001-stdout.txt
deleted file mode 100644
index 42a2f35..0000000
--- a/Tests/RunCMake/Ninja/ShowIncludes-65001-stdout.txt
+++ /dev/null
@@ -1 +0,0 @@
--- showIncludes='注意: 包含文件:'
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-check.cmake
new file mode 100644
index 0000000..10fa194
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-check.cmake
@@ -0,0 +1,3 @@
+# 'cl /showIncludes' prefix with 'VSLANG=1041' and 'chcp 932'.
+string(ASCII 131 129 131 130 58 32 131 67 131 147 131 78 131 139 129 91 131 104 32 131 116 131 64 131 67 131 139 58 32 32 expect)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-stdout.txt
new file mode 100644
index 0000000..4640616
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese-stdout.txt
@@ -0,0 +1 @@
+-- showIncludes='メモ: インクルード ファイル: '
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese.cmake b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese.cmake
new file mode 100644
index 0000000..ed8203c
--- /dev/null
+++ b/Tests/RunCMake/Ninja/ShowIncludes-932-Japanese.cmake
@@ -0,0 +1,3 @@
+set(CODEPAGE 932)
+set(VSLANG 1041)
+include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake)
diff --git a/Tests/RunCMake/Ninja/ShowIncludes-cmake.cmake b/Tests/RunCMake/Ninja/ShowIncludes-cmake.cmake
index 672a89f..5ed9970 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes-cmake.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes-cmake.cmake
@@ -1,6 +1,10 @@
# Set the console code page.
execute_process(COMMAND cmd /c chcp "${CODEPAGE}")
+if(VSLANG)
+ set(ENV{VSLANG} "${VSLANG}")
+endif()
+
if(RunCMake_MAKE_PROGRAM)
set(maybe_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
endif()
diff --git a/Tests/RunCMake/Ninja/ShowIncludes.cmake b/Tests/RunCMake/Ninja/ShowIncludes.cmake
index b9f89fe..a75c9bc 100644
--- a/Tests/RunCMake/Ninja/ShowIncludes.cmake
+++ b/Tests/RunCMake/Ninja/ShowIncludes.cmake
@@ -15,7 +15,7 @@ endif()
# Run cmake in a new Window to isolate its console code page.
execute_process(COMMAND cmd /c start /min /wait ""
- ${CMAKE_COMMAND} -DCODEPAGE=${CODEPAGE} ${maybe_MAKE_PROGRAM} -P ${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-cmake.cmake)
+ ${CMAKE_COMMAND} -DCODEPAGE=${CODEPAGE} -DVSLANG=${VSLANG} ${maybe_MAKE_PROGRAM} -P ${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-cmake.cmake)
# Print our internal UTF-8 representation of the showIncludes prefix.
file(READ "${CMAKE_CURRENT_BINARY_DIR}/showIncludes.txt" showIncludes_txt)
diff --git a/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
index a1ae6ac..30b24bf 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake
@@ -7,7 +7,8 @@ set(expected_compile_commands
]*Debug[^
]*",
"file": "[^
-]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)"
+]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)",
+ "output": "(CMakeFiles/exe\.dir/Debug/main\.c\.o|CMakeFiles\\\\exe\.dir\\\\Debug\\\\main\.c\.obj)"
},
{
"directory": "[^
@@ -16,7 +17,8 @@ set(expected_compile_commands
]*Release[^
]*",
"file": "[^
-]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)"
+]*(/Tests/RunCMake/NinjaMultiConfig/main\.c|\\\\Tests\\\\RunCMake\\\\NinjaMultiConfig\\\\main\.c)",
+ "output": "(CMakeFiles/exe\.dir/Release/main\.c\.o|CMakeFiles\\\\exe\.dir\\\\Release\\\\main\.c\.obj)"
}
]$]==])
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt
index 8877451..8c1c301 100644
--- a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-config-ninja-stdout.txt
@@ -1,4 +1,4 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: [^
]*/Tests/RunCMake/NinjaMultiConfig/Simple-build
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt
index 8877451..8c1c301 100644
--- a/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-reconfigure-noconfig-ninja-stdout.txt
@@ -1,4 +1,4 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: [^
]*/Tests/RunCMake/NinjaMultiConfig/Simple-build
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index ba9cc3b..54d7eb5 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -33,18 +33,18 @@ function(run_cmake test)
set(platform_name msys)
endif()
- foreach(o IN ITEMS out err)
- if(RunCMake-std${o}-file AND EXISTS ${top_src}/${RunCMake-std${o}-file})
- file(READ ${top_src}/${RunCMake-std${o}-file} expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
- elseif(EXISTS ${top_src}/${test}-std${o}-${platform_name}.txt)
- file(READ ${top_src}/${test}-std${o}-${platform_name}.txt expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
- elseif(EXISTS ${top_src}/${test}-std${o}.txt)
- file(READ ${top_src}/${test}-std${o}.txt expect_std${o})
- string(REGEX REPLACE "\n+$" "" expect_std${o} "${expect_std${o}}")
+ foreach(o IN ITEMS stdout stderr config)
+ if(RunCMake-${o}-file AND EXISTS ${top_src}/${RunCMake-${o}-file})
+ file(READ ${top_src}/${RunCMake-${o}-file} expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}-${platform_name}.txt)
+ file(READ ${top_src}/${test}-${o}-${platform_name}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
+ elseif(EXISTS ${top_src}/${test}-${o}.txt)
+ file(READ ${top_src}/${test}-${o}.txt expect_${o})
+ string(REGEX REPLACE "\n+$" "" expect_${o} "${expect_${o}}")
else()
- unset(expect_std${o})
+ unset(expect_${o})
endif()
endforeach()
if (NOT expect_stderr)
@@ -144,6 +144,12 @@ function(run_cmake test)
if(NOT "${actual_result}" MATCHES "${expect_result}")
string(APPEND msg "Result is [${actual_result}], not [${expect_result}].\n")
endif()
+ set(config_file "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}/CMakeFiles/CMakeConfigureLog.yaml")
+ if(EXISTS "${config_file}")
+ file(READ "${config_file}" actual_config)
+ else()
+ set(actual_config "")
+ endif()
# Special case: remove ninja no-op line from stderr, but not stdout.
# Test cases that look for it should use RunCMake_TEST_OUTPUT_MERGE.
@@ -155,6 +161,7 @@ function(run_cmake test)
"|BullseyeCoverage"
"|[a-z]+\\([0-9]+\\) malloc:"
"|clang[^:]*: warning: the object size sanitizer has no effect at -O0, but is explicitly enabled:"
+ "|icp?x: remark: Note that use of .-g. without any optimization-level option will turn off most compiler optimizations"
"|lld-link: warning: procedure symbol record for .* refers to PDB item index [0-9A-Fa-fx]+ which is not a valid function ID record"
"|Error kstat returned"
"|Hit xcodebuild bug"
@@ -179,17 +186,13 @@ function(run_cmake test)
"|[^\n]*Bullseye Testing Technology"
")[^\n]*\n)+"
)
- foreach(o IN ITEMS out err)
- string(REGEX REPLACE "\r\n" "\n" actual_std${o} "${actual_std${o}}")
- string(REGEX REPLACE "${ignore_line_regex}" "\\1" actual_std${o} "${actual_std${o}}")
- string(REGEX REPLACE "\n+$" "" actual_std${o} "${actual_std${o}}")
- set(expect_${o} "")
- if(DEFINED expect_std${o})
- if(NOT "${actual_std${o}}" MATCHES "${expect_std${o}}")
- string(REGEX REPLACE "\n" "\n expect-${o}> " expect_${o}
- " expect-${o}> ${expect_std${o}}")
- set(expect_${o} "Expected std${o} to match:\n${expect_${o}}\n")
- string(APPEND msg "std${o} does not match that expected.\n")
+ foreach(o IN ITEMS stdout stderr config)
+ string(REGEX REPLACE "\r\n" "\n" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "${ignore_line_regex}" "\\1" actual_${o} "${actual_${o}}")
+ string(REGEX REPLACE "\n+$" "" actual_${o} "${actual_${o}}")
+ if(DEFINED expect_${o})
+ if(NOT "${actual_${o}}" MATCHES "${expect_${o}}")
+ string(APPEND msg "${o} does not match that expected.\n")
endif()
endif()
endforeach()
@@ -214,15 +217,17 @@ function(run_cmake test)
string(APPEND msg "Command was:\n command> ${command}\n")
endif()
if(msg)
- string(REGEX REPLACE "\n" "\n actual-out> " actual_out " actual-out> ${actual_stdout}")
- string(REGEX REPLACE "\n" "\n actual-err> " actual_err " actual-err> ${actual_stderr}")
- message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n"
- "${msg}"
- "${expect_out}"
- "Actual stdout:\n${actual_out}\n"
- "${expect_err}"
- "Actual stderr:\n${actual_err}\n"
- )
+ foreach(o IN ITEMS stdout stderr config)
+ if(DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n expect-${o}> " expect_${o} " expect-${o}> ${expect_${o}}")
+ string(APPEND msg "Expected ${o} to match:\n${expect_${o}}\n")
+ endif()
+ if(NOT o STREQUAL "config" OR DEFINED expect_${o})
+ string(REGEX REPLACE "\n" "\n actual-${o}> " actual_${o} " actual-${o}> ${actual_${o}}")
+ string(APPEND msg "Actual ${o}:\n${actual_${o}}\n")
+ endif()
+ endforeach()
+ message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n${msg}")
else()
message(STATUS "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - PASSED")
endif()
diff --git a/Tests/RunCMake/RunCTest.cmake b/Tests/RunCMake/RunCTest.cmake
index 59db395..d46f6ad 100644
--- a/Tests/RunCMake/RunCTest.cmake
+++ b/Tests/RunCMake/RunCTest.cmake
@@ -1,5 +1,10 @@
include(RunCMake)
+# Isolate our ctest runs from external environment.
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+unset(ENV{CTEST_NO_TESTS_ACTION})
+
function(run_ctest CASE_NAME)
configure_file(${RunCMake_SOURCE_DIR}/test.cmake.in
${RunCMake_BINARY_DIR}/${CASE_NAME}/test.cmake @ONLY)
diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt b/Tests/RunCMake/Swift/IncrementalSwift-second-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-result.txt
+++ b/Tests/RunCMake/Swift/IncrementalSwift-second-result.txt
diff --git a/Tests/RunCMake/Swift/IncrementalSwift-second-stderr.txt b/Tests/RunCMake/Swift/IncrementalSwift-second-stderr.txt
new file mode 100644
index 0000000..7a882f8
--- /dev/null
+++ b/Tests/RunCMake/Swift/IncrementalSwift-second-stderr.txt
@@ -0,0 +1,2 @@
+ninja explain: A.swiftmodule is dirty
+ninja explain: libB.a is dirty
diff --git a/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt b/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt
new file mode 100644
index 0000000..bb08a49
--- /dev/null
+++ b/Tests/RunCMake/Swift/IncrementalSwift-second-stdout.txt
@@ -0,0 +1,3 @@
+.*Linking Swift static library libA.a
+.*Linking Swift static library libB.a
+FAILED: libB.a CMakeFiles/B.dir/b.swift.o B.swiftmodule
diff --git a/Tests/RunCMake/Swift/IncrementalSwift.cmake b/Tests/RunCMake/Swift/IncrementalSwift.cmake
new file mode 100644
index 0000000..092269f
--- /dev/null
+++ b/Tests/RunCMake/Swift/IncrementalSwift.cmake
@@ -0,0 +1,22 @@
+enable_language(Swift)
+
+# Write initial files to build directory
+# The files are generated into the build directory to avoid dirtying the source
+# directory. This is done because the source files are changed during the test
+# to ensure correct incremental build behavior.
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/a.swift
+ "let number: Int = 32\n"
+ "public func callA() -> Int { return number }\n")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/b.swift
+ "import A\n"
+ "public func callB() -> Int { return callA() + 1 }\n")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/exec.swift
+ "import B\n"
+ "print(callB())\n")
+
+add_library(A STATIC ${CMAKE_CURRENT_BINARY_DIR}/a.swift)
+add_library(B STATIC ${CMAKE_CURRENT_BINARY_DIR}/b.swift)
+target_link_libraries(B PRIVATE A)
+
+add_executable(exec ${CMAKE_CURRENT_BINARY_DIR}/exec.swift)
+target_link_libraries(exec PRIVATE B)
diff --git a/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt b/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt
new file mode 100644
index 0000000..60a9228
--- /dev/null
+++ b/Tests/RunCMake/Swift/NoWorkToDo-nowork-stdout.txt
@@ -0,0 +1 @@
+^ninja: no work to do
diff --git a/Tests/RunCMake/Swift/NoWorkToDo.cmake b/Tests/RunCMake/Swift/NoWorkToDo.cmake
new file mode 100644
index 0000000..51c2ff3
--- /dev/null
+++ b/Tests/RunCMake/Swift/NoWorkToDo.cmake
@@ -0,0 +1,5 @@
+enable_language(Swift)
+add_executable(hello1 hello.swift)
+set_target_properties(hello1 PROPERTIES ENABLE_EXPORTS TRUE)
+
+add_executable(hello2 hello.swift)
diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake
index 21d5a25..5537c01 100644
--- a/Tests/RunCMake/Swift/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake
@@ -14,6 +14,37 @@ elseif(RunCMake_GENERATOR STREQUAL Ninja)
run_cmake(SwiftMultiArch)
unset(RunCMake_TEST_OPTIONS)
endif()
+
+ # Test that a second build with no changes does nothing.
+ block()
+ run_cmake(NoWorkToDo)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/NoWorkToDo-build)
+ set(RunCMake_TEST_OUTPUT_MERGE 1)
+ run_cmake_command(NoWorkToDo-build ${CMAKE_COMMAND} --build .)
+ run_cmake_command(NoWorkToDo-nowork ${CMAKE_COMMAND} --build . -- -d explain)
+ endblock()
+
+ # Test that intermediate static libraries are rebuilt when the public
+ # interface of their dependency changes
+ block()
+ set(IncrementalSwift_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/IncrementalSwift-build)
+ set(IncrementalSwift_TEST_NO_CLEAN 1)
+ set(IncrementalSwift_TEST_OUTPUT_MERGE 1)
+ # Since files are modified during test, the files are created in the cmake
+ # file into the build directory
+ run_cmake(IncrementalSwift)
+ run_cmake_command(IncrementalSwift-first ${CMAKE_COMMAND} --build ${IncrementalSwift_TEST_BINARY_DIR})
+
+ # Modify public interface of libA requiring rebuild of libB
+ file(WRITE ${IncrementalSwift_TEST_BINARY_DIR}/a.swift
+ "public func callA() -> Float { return 32.0 }\n")
+
+ # Note: We still expect this to fail, but instead of failure at link time,
+ # it should fail while re-compiling libB because the function changed
+ run_cmake_command(IncrementalSwift-second ${CMAKE_COMMAND} --build ${IncrementalSwift_TEST_BINARY_DIR} -- -d explain)
+ endblock()
+
endif()
elseif(RunCMake_GENERATOR STREQUAL "Ninja Multi-Config")
if(CMAKE_Swift_COMPILER)
diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt b/Tests/RunCMake/Swift/hello.swift
index e69de29..e69de29 100644
--- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.txt
+++ b/Tests/RunCMake/Swift/hello.swift
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget.cmake b/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget.cmake
deleted file mode 100644
index 97d81e9..0000000
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/BadNonTarget.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
- "int main(int, char **) { return 0; }\n")
-
-add_executable(TargetPropertyGeneratorExpressions
- "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
-include_directories("$<TARGET_PROPERTY:NonExistent,INCLUDE_DIRECTORIES>")
diff --git a/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt b/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt
deleted file mode 100644
index c3922d6..0000000
--- a/Tests/RunCMake/TargetPropertyGeneratorExpressions/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-cmake_minimum_required(VERSION 3.3)
-project(${RunCMake_TEST} CXX)
-
-# MSVC creates extra targets which pollute the stderr unless we set this.
-set(CMAKE_SUPPRESS_REGENERATION TRUE)
-
-include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index f027e94..ed74896 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -89,3 +89,10 @@ run_cmake(VsDotnetTargetFramework)
run_cmake(VsDotnetTargetFrameworkVersion)
run_cmake(VsNoCompileBatching)
run_cmake(DebugInformationFormat)
+run_cmake(VsCLREmpty)
+run_cmake(VsCLRPure)
+run_cmake(VsCLRSafe)
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20)
+ run_cmake(VsCLRNetcore)
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake
new file mode 100644
index 0000000..990da46
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLREmpty-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+ set(propertyFound TRUE)
+ set(expectedValue "true")
+ set(actualValue ${CMAKE_MATCH_1})
+ if(NOT (${actualValue} STREQUAL ${expectedValue}))
+ set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+ return()
+ endif()
+ endif()
+endforeach()
+
+if(NOT propertyFound)
+ set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLREmpty.cmake b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake
new file mode 100644
index 0000000..a622f26
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLREmpty.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "")
diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake
new file mode 100644
index 0000000..a5058d7
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRNetcore-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<CLRSupport>(.*)</CLRSupport>$")
+ set(propertyFound TRUE)
+ set(expectedValue "NetCore")
+ set(actualValue ${CMAKE_MATCH_1})
+ if(NOT (${actualValue} STREQUAL ${expectedValue}))
+ set(RunCMake_TEST_FAILED "CLRSupport \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+ return()
+ endif()
+ endif()
+endforeach()
+
+if(NOT propertyFound)
+ set(RunCMake_TEST_FAILED "Property CLRSupport not found in project file.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake
new file mode 100644
index 0000000..c5ec2bc
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRNetcore.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "netcore")
diff --git a/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake
new file mode 100644
index 0000000..8ae73eb
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRPure-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+ set(propertyFound TRUE)
+ set(expectedValue "Pure")
+ set(actualValue ${CMAKE_MATCH_1})
+ if(NOT (${actualValue} STREQUAL ${expectedValue}))
+ set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+ return()
+ endif()
+ endif()
+endforeach()
+
+if(NOT propertyFound)
+ set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRPure.cmake b/Tests/RunCMake/VS10Project/VsCLRPure.cmake
new file mode 100644
index 0000000..f919a1c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRPure.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "pure")
diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake
new file mode 100644
index 0000000..ebb1f71
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRSafe-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(propertyFound FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<CompileAsManaged>(.*)</CompileAsManaged>$")
+ set(propertyFound TRUE)
+ set(expectedValue "Safe")
+ set(actualValue ${CMAKE_MATCH_1})
+ if(NOT (${actualValue} STREQUAL ${expectedValue}))
+ set(RunCMake_TEST_FAILED "CompileAsManaged \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+ return()
+ endif()
+ endif()
+endforeach()
+
+if(NOT propertyFound)
+ set(RunCMake_TEST_FAILED "Property CompileAsManaged not found in project file.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsCLRSafe.cmake b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake
new file mode 100644
index 0000000..5f114bf
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsCLRSafe.cmake
@@ -0,0 +1,6 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp)
+
+set_target_properties(foo PROPERTIES
+ COMMON_LANGUAGE_RUNTIME "safe")
diff --git a/Tests/RunCMake/VSSolution/CMP0143-NEW-check.cmake b/Tests/RunCMake/VSSolution/CMP0143-NEW-check.cmake
new file mode 100644
index 0000000..6dd042b
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-NEW-check.cmake
@@ -0,0 +1,6 @@
+getProjectNames(projects)
+
+list(FIND projects "CMakePredefinedTargets" found)
+ if(found EQUAL "-1")
+ error("CMakePredefinedTargets should be defined when CMP0143 is NEW!")
+endif()
diff --git a/Tests/RunCMake/VSSolution/CMP0143-NEW.cmake b/Tests/RunCMake/VSSolution/CMP0143-NEW.cmake
new file mode 100644
index 0000000..dd67b16
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-NEW.cmake
@@ -0,0 +1 @@
+add_custom_target(TestStartup)
diff --git a/Tests/RunCMake/VSSolution/CMP0143-OLD-check.cmake b/Tests/RunCMake/VSSolution/CMP0143-OLD-check.cmake
new file mode 100644
index 0000000..2d9829c
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-OLD-check.cmake
@@ -0,0 +1,6 @@
+getProjectNames(projects)
+
+list(FIND projects "CMakePredefinedTargets" found)
+ if(NOT (found EQUAL "-1"))
+ error("CMakePredefinedTargets should not be defined when CMP0143 is OLD!")
+endif()
diff --git a/Tests/RunCMake/VSSolution/CMP0143-OLD.cmake b/Tests/RunCMake/VSSolution/CMP0143-OLD.cmake
new file mode 100644
index 0000000..dd67b16
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-OLD.cmake
@@ -0,0 +1 @@
+add_custom_target(TestStartup)
diff --git a/Tests/RunCMake/VSSolution/CMP0143-WARN-check.cmake b/Tests/RunCMake/VSSolution/CMP0143-WARN-check.cmake
new file mode 100644
index 0000000..2d9829c
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-WARN-check.cmake
@@ -0,0 +1,6 @@
+getProjectNames(projects)
+
+list(FIND projects "CMakePredefinedTargets" found)
+ if(NOT (found EQUAL "-1"))
+ error("CMakePredefinedTargets should not be defined when CMP0143 is OLD!")
+endif()
diff --git a/Tests/RunCMake/VSSolution/CMP0143-WARN.cmake b/Tests/RunCMake/VSSolution/CMP0143-WARN.cmake
new file mode 100644
index 0000000..dd67b16
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-WARN.cmake
@@ -0,0 +1 @@
+add_custom_target(TestStartup)
diff --git a/Tests/RunCMake/VSSolution/RunCMakeTest.cmake b/Tests/RunCMake/VSSolution/RunCMakeTest.cmake
index c25833d..134821d 100644
--- a/Tests/RunCMake/VSSolution/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VSSolution/RunCMakeTest.cmake
@@ -15,4 +15,7 @@ run_cmake(AddPackageToDefault)
if(NOT NO_USE_FOLDERS)
run_cmake(StartupProjectUseFolders)
+ run_cmake(CMP0143-WARN)
+ run_cmake_with_options(CMP0143-OLD "-DCMAKE_POLICY_DEFAULT_CMP0143=OLD")
+ run_cmake_with_options(CMP0143-NEW "-DCMAKE_POLICY_DEFAULT_CMP0143=NEW")
endif()
diff --git a/Tests/RunCMake/VsDotnetSdk/App.xaml b/Tests/RunCMake/VsDotnetSdk/App.xaml
new file mode 100644
index 0000000..156e0fc
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/App.xaml
@@ -0,0 +1,9 @@
+<Application x:Class="Example.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:Example"
+ StartupUri="MainWindow.xaml">
+ <Application.Resources>
+
+ </Application.Resources>
+</Application>
diff --git a/Tests/RunCMake/VsDotnetSdk/App.xaml.cs b/Tests/RunCMake/VsDotnetSdk/App.xaml.cs
new file mode 100644
index 0000000..df2669e
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/App.xaml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Example
+{
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : Application
+ {
+ }
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml b/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml
new file mode 100644
index 0000000..9a8597d
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml
@@ -0,0 +1,12 @@
+<Window x:Class="Example.MainWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:local="clr-namespace:Example"
+ mc:Ignorable="d"
+ Title="MainWindow" Height="350" Width="525">
+ <Grid>
+
+ </Grid>
+</Window>
diff --git a/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml.cs b/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml.cs
new file mode 100644
index 0000000..7d059ed
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/MainWindow.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Example
+{
+ /// <summary>
+ /// Interaction logic for MainWindow.xaml
+ /// </summary>
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/Resources.Designer.cs b/Tests/RunCMake/VsDotnetSdk/Resources.Designer.cs
new file mode 100644
index 0000000..58ac7d0
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Tests/RunCMake/VsDotnetSdk/Resources.resx b/Tests/RunCMake/VsDotnetSdk/Resources.resx
new file mode 100644
index 0000000..ea9cbcd
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root>
diff --git a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
index 22e2bb3..34259b7 100644
--- a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
@@ -6,6 +6,7 @@ run_cmake(VsDotnetSdkCustomCommandsSource)
run_cmake(VsDotnetSdkStartupObject)
run_cmake(VsDotnetSdkDefines)
run_cmake(DotnetSdkVariables)
+run_cmake(VsDotnetSdkXamlFiles)
function(run_VsDotnetSdk)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VsDotnetSdk-build)
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles-check.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles-check.cmake
new file mode 100644
index 0000000..3e2c6de
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles-check.cmake
@@ -0,0 +1,56 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/dotNetSdkWpfApp.csproj")
+if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.")
+ return()
+endif()
+
+set(inAppDefinition FALSE)
+set(inPageDefinition FALSE)
+set(inResourceDefinition FALSE)
+set(xamlAppDefinitionSet FALSE)
+set(xamlPageSet FALSE)
+set(resourcesSet FALSE)
+
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(NOT inAppDefinition AND line MATCHES "^ *<ApplicationDefinition[^>]*>")
+ set(inAppDefinition TRUE)
+ elseif(inAppDefinition AND line MATCHES "^ *<Link>([^<>]+)</Link>$")
+ if("${CMAKE_MATCH_1}" STREQUAL "App.xaml")
+ message(STATUS "dotNetSdkWpfApp.csproj has app definition set")
+ set(xamlAppDefinitionSet TRUE)
+ set(inAppDefinition FALSE)
+ endif()
+ elseif(NOT inPageDefinition AND line MATCHES "^ *<Page[^>]*>")
+ set(inPageDefinition TRUE)
+ elseif(inPageDefinition AND line MATCHES "^ *<Link>([^<>]+)</Link>$")
+ if("${CMAKE_MATCH_1}" STREQUAL "MainWindow.xaml")
+ message(STATUS "dotNetSdkWpfApp.csproj has main window page set")
+ set(xamlPageSet TRUE)
+ set(inPageDefinition FALSE)
+ endif()
+ elseif(NOT inResourceDefinition AND line MATCHES "^ *<EmbeddedResource[^>]*>")
+ set(inResourceDefinition TRUE)
+ elseif(inResourceDefinition AND line MATCHES "^ *<Link>([^<>]+)</Link>$")
+ if("${CMAKE_MATCH_1}" STREQUAL "Resources.resx")
+ message(STATUS "dotNetSdkWpfApp.csproj has embedded resources set")
+ set(resourcesSet TRUE)
+ set(inResourceDefinition FALSE)
+ endif()
+ endif()
+endforeach()
+
+if(NOT xamlAppDefinitionSet)
+ set(RunCMake_TEST_FAILED "Xaml App definition not set correctly.")
+ return()
+endif()
+
+if(NOT xamlPageSet)
+ set(RunCMake_TEST_FAILED "Xaml Page not set correctly.")
+ return()
+endif()
+
+if(NOT resourcesSet)
+ set(RunCMake_TEST_FAILED "resources not set correctly.")
+ return()
+endif()
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles.cmake
new file mode 100644
index 0000000..8faf3a7
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkXamlFiles.cmake
@@ -0,0 +1,48 @@
+enable_language(CSharp)
+
+if(NOT CMAKE_CSharp_COMPILER)
+ return()
+endif()
+
+include(CSharpUtilities)
+
+add_executable(dotNetSdkWpfApp)
+target_sources(dotNetSdkWpfApp
+ PRIVATE
+ App.xaml
+ App.xaml.cs
+ MainWindow.xaml
+ MainWindow.xaml.cs
+ Resources.Designer.cs
+ Resources.resx)
+
+csharp_set_xaml_cs_properties(
+ App.xaml
+ App.xaml.cs
+ MainWindow.xaml
+ MainWindow.xaml.cs)
+
+csharp_set_designer_cs_properties(
+ Resources.Designer.cs
+ Resources.resx)
+
+set_target_properties(dotNetSdkWpfApp
+ PROPERTIES
+ DOTNET_SDK "Microsoft.NET.Sdk"
+ DOTNET_TARGET_FRAMEWORK "net5.0")
+
+set_property(SOURCE App.xaml PROPERTY VS_XAML_TYPE "ApplicationDefinition")
+
+set_property(TARGET dotNetSdkWpfApp PROPERTY VS_DOTNET_REFERENCES
+ "Microsoft.CSharp"
+ "PresentationCore"
+ "PresentationFramework"
+ "System"
+ "System.Core"
+ "System.Data"
+ "System.Data.DataSetExtensions"
+ "System.Net.Http"
+ "System.Xaml"
+ "System.Xml"
+ "System.Xml.Linq"
+ "WindowsBase")
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS-check.cmake
new file mode 100644
index 0000000..576be11
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS-check.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/findAttribute.cmake)
+
+findAttribute(${test} "RemoveHeadersOnCopy" TRUE)
+findAttribute(${test} "CodeSignOnCopy" FALSE)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS.cmake
new file mode 100644
index 0000000..839f842
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-iOS.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/EmbedAppExtensions.cmake)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS-check.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS-check.cmake
new file mode 100644
index 0000000..576be11
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS-check.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_LIST_DIR}/findAttribute.cmake)
+
+findAttribute(${test} "RemoveHeadersOnCopy" TRUE)
+findAttribute(${test} "CodeSignOnCopy" FALSE)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS.cmake
new file mode 100644
index 0000000..839f842
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions-macOS.cmake
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/EmbedAppExtensions.cmake)
diff --git a/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions.cmake b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions.cmake
new file mode 100644
index 0000000..91d207b
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/EmbedExtensionKitExtensions.cmake
@@ -0,0 +1,22 @@
+add_executable(app_extensionkit_extension main.m)
+set_target_properties(app_extensionkit_extension PROPERTIES
+ LINKER_LANGUAGE CXX
+ BUNDLE YES
+ XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
+ XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
+ XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE "YES"
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ExtensionKit.Info.plist.in"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "com.example.app.app_extensionkit_extension"
+ XCODE_PRODUCT_TYPE "com.apple.product-type.extensionkit-extension"
+ XCODE_EXPLICIT_FILE_TYPE "wrapper.extensionkit-extension"
+)
+
+add_executable(app MACOSX_BUNDLE main.m)
+add_dependencies(app app_extension)
+set_target_properties(app PROPERTIES
+ XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
+ XCODE_EMBED_EXTENSIONKIT_EXTENSIONS app_extension
+ MACOSX_BUNDLE_GUI_IDENTIFIER "com.example.app"
+)
diff --git a/Tests/RunCMake/XcodeProject-Embed/ExtensionKit.Info.plist.in b/Tests/RunCMake/XcodeProject-Embed/ExtensionKit.Info.plist.in
new file mode 100644
index 0000000..573aa22
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject-Embed/ExtensionKit.Info.plist.in
@@ -0,0 +1,13 @@
+<?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>EXAppExtensionAttributes</key>
+ <dict>
+ <key>EXExtensionPointIdentifier</key>
+ <string>com.apple.background-asset-downloader-extension</string>
+ <key>EXPrincipalClass</key>
+ <string>BackgroundDownloadHandler</string>
+ </dict>
+</dict>
+</plist>
diff --git a/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
index f3a6918..a7bccee 100644
--- a/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject-Embed/RunCMakeTest.cmake
@@ -64,6 +64,25 @@ function(TestAppExtension platform)
)
endfunction()
+function(TestExtensionKitExtension platform)
+ set(testName EmbedExtensionKitExtensions-${platform})
+ if(NOT platform STREQUAL "macOS")
+ set(RunCMake_TEST_OPTIONS -DCMAKE_SYSTEM_NAME=${platform})
+ endif()
+ set(RunCMake_TEST_NO_CLEAN 1)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${testName}-build)
+
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+ run_cmake(${testName})
+ run_cmake_command(${testName}-build
+ ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR}
+ --config Debug
+ --target app
+ )
+endfunction()
+
# Isolate device tests from host architecture selection.
unset(ENV{CMAKE_OSX_ARCHITECTURES})
@@ -74,3 +93,11 @@ if(XCODE_VERSION VERSION_GREATER_EQUAL 8)
TestAppExtension(macOS)
TestAppExtension(iOS)
endif()
+
+if(XCODE_VERSION VERSION_GREATER_EQUAL 14.1)
+ # The various flag on/off combinations are tested by the EmbedFrameworks...
+ # tests, so we don't duplicate all the combinations here. We only verify the
+ # defaults, which is to remove headers on copy, but not code sign.
+ TestAppExtension(macOS)
+ TestAppExtension(iOS)
+endif()
diff --git a/Tests/RunCMake/XcodeProject/InheritedParameters-check.cmake b/Tests/RunCMake/XcodeProject/InheritedParameters-check.cmake
index 4fe42ac..59e3f4b 100644
--- a/Tests/RunCMake/XcodeProject/InheritedParameters-check.cmake
+++ b/Tests/RunCMake/XcodeProject/InheritedParameters-check.cmake
@@ -7,6 +7,8 @@ endif()
set(found_inherited_GCC_PREPROCESSOR_DEFINITIONS 1)
set(found_inherited_OTHER_CFLAGS 1)
set(found_inherited_OTHER_LDFLAGS 1)
+set(found_inherited_OTHER_SWIFT_FLAGS 1)
+set(found_inherited_SWIFT_ACTIVE_COMPILATION_CONDITIONS 1)
file(STRINGS "${xcProjectFile}" lines)
foreach(line IN LISTS lines)
@@ -32,6 +34,20 @@ foreach(line IN LISTS lines)
endif()
endif()
+ if(line MATCHES [[OTHER_SWIFT_FLAGS]])
+ if(NOT line MATCHES [["\$\(inherited\)"]])
+ string(APPEND relevant_lines " ${line}\n")
+ set(found_inherited_OTHER_SWIFT_FLAGS 0)
+ endif()
+ endif()
+
+ if(line MATCHES [[SWIFT_ACTIVE_COMPILATION_CONDITIONS]])
+ if(NOT line MATCHES [["\$\(inherited\)"]])
+ string(APPEND relevant_lines " ${line}\n")
+ set(found_inherited_SWIFT_ACTIVE_COMPILATION_CONDITIONS 0)
+ endif()
+ endif()
+
endforeach()
if(NOT found_inherited_GCC_PREPROCESSOR_DEFINITIONS)
@@ -43,6 +59,14 @@ endif()
if(NOT found_inherited_OTHER_LDFLAGS)
string(APPEND RunCMake_TEST_FAILED "Found missing inherited value for OTHER_LDFLAGS in\n ${xcProjectFile}\n")
endif()
+if(CMake_TEST_Swift)
+ if(NOT found_inherited_OTHER_SWIFT_FLAGS)
+ string(APPEND RunCMake_TEST_FAILED "Found missing inherited value for OTHER_SWIFT_FLAGS in\n ${xcProjectFile}\n")
+ endif()
+ if(NOT found_inherited_SWIFT_ACTIVE_COMPILATION_CONDITIONS)
+ string(APPEND RunCMake_TEST_FAILED "Found missing inherited value for SWIFT_ACTIVE_COMPILATION_CONDITIONS in\n ${xcProjectFile}\n")
+ endif()
+endif()
if(RunCMake_TEST_FAILED)
string(APPEND RunCMake_TEST_FAILED "Relevant lines include\n${relevant_lines}")
diff --git a/Tests/RunCMake/XcodeProject/InheritedParameters.cmake b/Tests/RunCMake/XcodeProject/InheritedParameters.cmake
index 5b8ec71..e2cc2a7 100644
--- a/Tests/RunCMake/XcodeProject/InheritedParameters.cmake
+++ b/Tests/RunCMake/XcodeProject/InheritedParameters.cmake
@@ -1,4 +1,9 @@
enable_language(C)
+if(CMake_TEST_Swift)
+ enable_language(Swift)
+ string(APPEND CMAKE_Swift_FLAGS " -DSWIFTFLAG")
+ add_executable(swift_inherit_test dummy_main.swift)
+endif()
add_compile_definitions(TEST_INHERITTEST)
string(APPEND CMAKE_C_FLAGS " -DTESTFLAG=\\\"TEST_INHERITTEST\\\"")
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 573d5f7..3910127 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -13,7 +13,7 @@ run_cmake(ExplicitCMakeLists)
run_cmake(ImplicitCMakeLists)
run_cmake(InterfaceLibSources)
run_cmake_with_options(SearchPaths -DCMAKE_CONFIGURATION_TYPES=Debug)
-run_cmake(InheritedParameters)
+run_cmake_with_options(InheritedParameters -DCMake_TEST_Swift=${CMake_TEST_Swift})
run_cmake(XcodeFileType)
run_cmake(XcodeAttributeLocation)
diff --git a/Tests/RunCMake/add_compile_definitions/CMakeLists.txt b/Tests/RunCMake/add_compile_definitions/CMakeLists.txt
new file mode 100644
index 0000000..14ef56e
--- /dev/null
+++ b/Tests/RunCMake/add_compile_definitions/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.11)
+
+project(${RunCMake_TEST} LANGUAGES NONE)
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/add_compile_definitions/RunCMakeTest.cmake b/Tests/RunCMake/add_compile_definitions/RunCMakeTest.cmake
new file mode 100644
index 0000000..27d77ef
--- /dev/null
+++ b/Tests/RunCMake/add_compile_definitions/RunCMakeTest.cmake
@@ -0,0 +1,13 @@
+include(RunCMake)
+
+macro(run_cmake_build test)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test} ${CMAKE_COMMAND} --build . --config Release)
+
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+run_cmake(remove_leading_minusD)
+run_cmake_build(remove_leading_minusD)
diff --git a/Tests/RunCMake/add_compile_definitions/foo.c b/Tests/RunCMake/add_compile_definitions/foo.c
new file mode 100644
index 0000000..74a86e1
--- /dev/null
+++ b/Tests/RunCMake/add_compile_definitions/foo.c
@@ -0,0 +1,4 @@
+
+void foo()
+{
+}
diff --git a/Tests/RunCMake/add_compile_definitions/remove_leading_minusD.cmake b/Tests/RunCMake/add_compile_definitions/remove_leading_minusD.cmake
new file mode 100644
index 0000000..0d94340
--- /dev/null
+++ b/Tests/RunCMake/add_compile_definitions/remove_leading_minusD.cmake
@@ -0,0 +1,6 @@
+
+enable_language(C)
+
+add_compile_definitions(-DDEF0 "$<1:-DDEF1>")
+
+add_library(lib1 foo.c)
diff --git a/Tests/RunCMake/add_custom_command/CommentGenex-build-stdout.txt b/Tests/RunCMake/add_custom_command/CommentGenex-build-stdout.txt
new file mode 100644
index 0000000..bf49657
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CommentGenex-build-stdout.txt
@@ -0,0 +1 @@
+lorem ipsum, 01
diff --git a/Tests/RunCMake/add_custom_command/CommentGenex.cmake b/Tests/RunCMake/add_custom_command/CommentGenex.cmake
new file mode 100644
index 0000000..f517392
--- /dev/null
+++ b/Tests/RunCMake/add_custom_command/CommentGenex.cmake
@@ -0,0 +1,9 @@
+add_custom_target(helper)
+set_property(TARGET helper PROPERTY MY_TEXT "lorem ipsum")
+add_custom_command(
+ OUTPUT out.txt
+ COMMAND ${CMAKE_COMMAND} -E echo true
+ COMMENT "$<TARGET_PROPERTY:helper,MY_TEXT>$<COMMA> $<STREQUAL:foo,bar>$<EQUAL:42,42>"
+)
+set_property(SOURCE out.txt PROPERTY SYMBOLIC 1)
+add_custom_target(main ALL DEPENDS out.txt)
diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
index ad6b258..6c677c0 100644
--- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake
@@ -60,3 +60,12 @@ function(test_genex name)
endfunction()
test_genex(TargetGenexEvent)
+
+if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
+ block()
+ run_cmake(CommentGenex)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommentGenex-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(CommentGenex-build ${CMAKE_COMMAND} --build .)
+ endblock()
+endif()
diff --git a/Tests/RunCMake/add_custom_target/CommentGenex-build-stdout.txt b/Tests/RunCMake/add_custom_target/CommentGenex-build-stdout.txt
new file mode 100644
index 0000000..bf49657
--- /dev/null
+++ b/Tests/RunCMake/add_custom_target/CommentGenex-build-stdout.txt
@@ -0,0 +1 @@
+lorem ipsum, 01
diff --git a/Tests/RunCMake/add_custom_target/CommentGenex.cmake b/Tests/RunCMake/add_custom_target/CommentGenex.cmake
new file mode 100644
index 0000000..6e6706e
--- /dev/null
+++ b/Tests/RunCMake/add_custom_target/CommentGenex.cmake
@@ -0,0 +1,6 @@
+add_custom_target(helper)
+set_property(TARGET helper PROPERTY MY_TEXT "lorem ipsum")
+add_custom_target(main ALL
+ COMMAND ${CMAKE_COMMAND} -E true
+ COMMENT "$<TARGET_PROPERTY:helper,MY_TEXT>$<COMMA> $<STREQUAL:foo,bar>$<EQUAL:42,42>"
+)
diff --git a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
index 22a9ed4..f43779b 100644
--- a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake
@@ -23,3 +23,12 @@ function(run_TargetOrder)
run_cmake_command(TargetOrder-build ${CMAKE_COMMAND} --build . -- ${build_flags})
endfunction()
run_TargetOrder()
+
+if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
+ block()
+ run_cmake(CommentGenex)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommentGenex-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(CommentGenex-build ${CMAKE_COMMAND} --build .)
+ endblock()
+endif()
diff --git a/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt
new file mode 100644
index 0000000..f5247ca
--- /dev/null
+++ b/Tests/RunCMake/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at duplicate-target-CMP0107-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0107 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt b/Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt
index 34c873c..9f4f24e 100644
--- a/Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt
+++ b/Tests/RunCMake/configure_file/RerunCMake-rerun-stdout.txt
@@ -1,3 +1,3 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: .*/Tests/RunCMake/configure_file/RerunCMake-build
diff --git a/Tests/RunCMake/configure_file/RerunCMake-stdout.txt b/Tests/RunCMake/configure_file/RerunCMake-stdout.txt
index 34c873c..9f4f24e 100644
--- a/Tests/RunCMake/configure_file/RerunCMake-stdout.txt
+++ b/Tests/RunCMake/configure_file/RerunCMake-stdout.txt
@@ -1,3 +1,3 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: .*/Tests/RunCMake/configure_file/RerunCMake-build
diff --git a/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake b/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake
index 365c9e8..4716c41 100644
--- a/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_environment/RunCMakeTest.cmake
@@ -1,9 +1,5 @@
include(RunCTest)
-# Isolate our ctest runs from external environment.
-unset(ENV{CTEST_PARALLEL_LEVEL})
-unset(ENV{CTEST_OUTPUT_ON_FAILURE})
-
set(CASE_SOURCE_DIR "${RunCMake_SOURCE_DIR}")
set(RunCTest_VERBOSE_FLAG "-VV")
diff --git a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
index 1754203..1c2ad89 100644
--- a/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_fixtures/RunCMakeTest.cmake
@@ -1,9 +1,5 @@
include(RunCTest)
-# Isolate our ctest runs from external environment.
-unset(ENV{CTEST_PARALLEL_LEVEL})
-unset(ENV{CTEST_OUTPUT_ON_FAILURE})
-
function(run_ctest_test CASE_NAME)
set(CASE_CTEST_FIXTURES_ARGS "${ARGN}")
run_ctest(${CASE_NAME})
diff --git a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
index cb8f696..3f6501e 100644
--- a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
@@ -4,8 +4,6 @@ set(SITE test-site)
set(BUILDNAME test-build)
set(COVERAGE_COMMAND "")
-unset(ENV{CTEST_PARALLEL_LEVEL})
-
function(run_mc_test CASE_NAME CHECKER_COMMAND)
run_ctest(${CASE_NAME} ${ARGN})
endfunction()
diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
index 74ae99c..242a059 100644
--- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
@@ -1,9 +1,6 @@
include(RunCTest)
set(RunCMake_TEST_TIMEOUT 60)
-unset(ENV{CTEST_PARALLEL_LEVEL})
-unset(ENV{CTEST_OUTPUT_ON_FAILURE})
-
set(CASE_CTEST_TEST_ARGS "")
set(CASE_CTEST_TEST_LOAD "")
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt
new file mode 100644
index 0000000..1183f86
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Repeat-CMP0103-OLD.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0103 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt b/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt
new file mode 100644
index 0000000..9a66cde
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.13)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt
new file mode 100644
index 0000000..bd1727a
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH-stdout.txt
@@ -0,0 +1,8 @@
+-- status='0;"No error"'
+-- status='0;"skipping download as file already exists with expected MD5 sum"'
+-- status='0;"skipping download as file already exists with expected MD5 hash"'
+-- status='0;"skipping download as file already exists with expected SHA1 hash"'
+-- status='0;"skipping download as file already exists with expected SHA224 hash"'
+-- status='0;"skipping download as file already exists with expected SHA256 hash"'
+-- status='0;"skipping download as file already exists with expected SHA384 hash"'
+-- status='0;"skipping download as file already exists with expected SHA512 hash"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake
new file mode 100644
index 0000000..dc7f8ff
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/EXPECTED_HASH.cmake
@@ -0,0 +1,13 @@
+include(common.cmake)
+
+# Actually download the file and verify its hash.
+file_download(EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92)
+
+# Verify that the local file already exists with expected hash.
+file_download(EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92)
+file_download(EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92)
+file_download(EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578)
+file_download(EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4)
+file_download(EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423)
+file_download(EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950)
+file_download(EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b)
diff --git a/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake b/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake
new file mode 100644
index 0000000..d757eea
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/RunCMakeTest.cmake
@@ -0,0 +1,31 @@
+include(RunCMake)
+
+# We do not contact any real URLs, but do try a bogus one.
+# Remove any proxy configuration that may change behavior.
+unset(ENV{http_proxy})
+unset(ENV{https_proxy})
+
+run_cmake(hash-mismatch)
+run_cmake(unused-argument)
+run_cmake(httpheader-not-set)
+run_cmake(netrc-bad)
+run_cmake(tls-cainfo-not-set)
+run_cmake(tls-verify-not-set)
+run_cmake(pass-not-set)
+run_cmake(no-save-hash)
+
+run_cmake(basic)
+run_cmake(EXPECTED_HASH)
+run_cmake(file-without-path)
+run_cmake(no-file)
+run_cmake(range)
+run_cmake(SHOW_PROGRESS)
+
+if(NOT CMake_TEST_NO_NETWORK)
+ run_cmake(bad-hostname)
+endif()
+
+if(CMake_TEST_TLS_VERIFY_URL)
+ run_cmake(TLS_VERIFY-bad)
+ run_cmake_with_options(TLS_VERIFY-good -Durl=${CMake_TEST_TLS_VERIFY_URL})
+endif()
diff --git a/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt
new file mode 100644
index 0000000..e0a4982
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS-stdout.txt
@@ -0,0 +1,2 @@
+-- \[download 100% complete\]
+-- status='0;"No error"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake
new file mode 100644
index 0000000..ccabced
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/SHOW_PROGRESS.cmake
@@ -0,0 +1,3 @@
+include(common.cmake)
+
+file_download(SHOW_PROGRESS)
diff --git a/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad-stdout.txt
new file mode 100644
index 0000000..8f5d437
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad-stdout.txt
@@ -0,0 +1 @@
+-- (60;"SSL peer certificate or SSH remote key was not OK"|35;"SSL connect error")
diff --git a/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad.cmake b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad.cmake
new file mode 100644
index 0000000..333f990
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-bad.cmake
@@ -0,0 +1,6 @@
+file(DOWNLOAD https://expired.badssl.com TLS_VERIFY 1 STATUS status LOG log)
+message(STATUS "${status}")
+list(GET status 0 code)
+if(NOT code MATCHES "^(35|60)$")
+ message("${log}")
+endif()
diff --git a/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good-stdout.txt
new file mode 100644
index 0000000..348bb17
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good-stdout.txt
@@ -0,0 +1 @@
+-- 0;"No error"
diff --git a/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good.cmake b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good.cmake
new file mode 100644
index 0000000..279eb69
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/TLS_VERIFY-good.cmake
@@ -0,0 +1,6 @@
+file(DOWNLOAD ${url} TLS_VERIFY 1 STATUS status LOG log)
+message(STATUS "${status}")
+list(GET status 0 code)
+if(NOT code EQUAL 0)
+ message("${log}")
+endif()
diff --git a/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt
new file mode 100644
index 0000000..12278e0
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/bad-hostname-stdout.txt
@@ -0,0 +1 @@
+-- status='6;"Couldn't resolve host name"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake b/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake
new file mode 100644
index 0000000..d3b7a28
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/bad-hostname.cmake
@@ -0,0 +1,9 @@
+include(common.cmake)
+
+# Do not use any proxy for lookup of an invalid site.
+# DNS failure by proxy looks different than DNS failure without proxy.
+set(ENV{no_proxy} "$ENV{no_proxy},badhostname.invalid")
+
+set(url "badhostname.invalid")
+
+file_download()
diff --git a/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt
new file mode 100644
index 0000000..701e995
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/basic-stdout.txt
@@ -0,0 +1 @@
+-- status='0;"No error"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/basic.cmake b/Tests/RunCMake/file-DOWNLOAD/basic.cmake
new file mode 100644
index 0000000..1fd931c
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/basic.cmake
@@ -0,0 +1,3 @@
+include(common.cmake)
+
+file_download()
diff --git a/Tests/RunCMake/file-DOWNLOAD/common.cmake b/Tests/RunCMake/file-DOWNLOAD/common.cmake
new file mode 100644
index 0000000..6aa2fe6
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/common.cmake
@@ -0,0 +1,15 @@
+if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
+ set(slash /)
+endif()
+set(url "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/input.png")
+set(file ${CMAKE_CURRENT_BINARY_DIR}/output.png)
+
+function(file_download)
+ file(DOWNLOAD "${url}"
+ ${file} # leave unquoted
+ TIMEOUT 30
+ STATUS status
+ ${ARGN}
+ )
+ message(STATUS "status='${status}'")
+endfunction()
diff --git a/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt
new file mode 100644
index 0000000..701e995
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/file-without-path-stdout.txt
@@ -0,0 +1 @@
+-- status='0;"No error"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake b/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake
new file mode 100644
index 0000000..a628423
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/file-without-path.cmake
@@ -0,0 +1,10 @@
+include(common.cmake)
+
+set(file_orig "${file}")
+cmake_path(GET file_orig FILENAME file)
+
+file_download()
+
+if(NOT EXISTS "${file_orig}")
+ message(FATAL_ERROR "file not downloaded to expected path:\n ${file_orig}")
+endif()
diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-result.txt
diff --git a/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt
new file mode 100644
index 0000000..6682794
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at hash-mismatch.cmake:[0-9]+ \(file\):
+ file DOWNLOAD HASH mismatch
+
+ for file: \[.*/Tests/RunCMake/file-DOWNLOAD/hash-mismatch-build/output.png\]
+ expected hash: \[0123456789abcdef0123456789abcdef01234567\]
+ actual hash: \[67eee17f79d9ac557284fc0b8ad19f25723fb578\]
+
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
++
+status='1;HASH mismatch: expected: 0123456789abcdef0123456789abcdef01234567 actual: 67eee17f79d9ac557284fc0b8ad19f25723fb578'$
diff --git a/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake
new file mode 100644
index 0000000..e3f91e3
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/hash-mismatch.cmake
@@ -0,0 +1,8 @@
+include(common.cmake)
+
+file(DOWNLOAD ${url} ${file}
+ EXPECTED_HASH SHA1=0123456789abcdef0123456789abcdef01234567
+ TIMEOUT 30
+ STATUS status
+ )
+message("status='${status}'")
diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-result.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-result.txt
diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-stderr.txt
index 247923b..3ac5082 100644
--- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set-stderr.txt
@@ -1,4 +1,4 @@
-^CMake Error at DOWNLOAD-httpheader-not-set.cmake:[0-9]+ \(file\):
+^CMake Error at httpheader-not-set.cmake:[0-9]+ \(file\):
file DOWNLOAD missing string for HTTPHEADER.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set.cmake
index 6efc958..6efc958 100644
--- a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake
+++ b/Tests/RunCMake/file-DOWNLOAD/httpheader-not-set.cmake
diff --git a/Tests/RunCMake/file-DOWNLOAD/input.png b/Tests/RunCMake/file-DOWNLOAD/input.png
new file mode 100644
index 0000000..9ab565a
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/input.png
Binary files differ
diff --git a/Tests/RunCMake/Configure/ErrorLogs-result.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/Configure/ErrorLogs-result.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-result.txt
diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-stderr.txt
index 96ce62a..61d7c99 100644
--- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad-stderr.txt
@@ -1,19 +1,19 @@
-^CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\):
+^CMake Error at netrc-bad\.cmake:[0-9]+ \(file\):
file DOWNLOAD missing level value for NETRC\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
-CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\):
+CMake Error at netrc-bad\.cmake:[0-9]+ \(file\):
file DOWNLOAD missing file value for NETRC_FILE\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
-CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\):
+CMake Error at netrc-bad\.cmake:[0-9]+ \(file\):
file NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: INVALID
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
+
-CMake Error at DOWNLOAD-netrc-bad\.cmake:[0-9]+ \(file\):
+CMake Error at netrc-bad\.cmake:[0-9]+ \(file\):
file NETRC accepts OPTIONAL, IGNORED or REQUIRED but got: FALSE
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.cmake
index 6a62df9..c62238a 100644
--- a/Tests/RunCMake/file/DOWNLOAD-netrc-bad.cmake
+++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.cmake
@@ -5,11 +5,11 @@ file(DOWNLOAD "" "" NETRC)
file(DOWNLOAD "" "" NETRC_FILE)
set(CMAKE_NETRC FALSE)
file(DOWNLOAD
- "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-netrc-bad.txt"
+ "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/netrc-bad.txt"
"${CMAKE_CURRENT_BINARY_DIR}/netrc-bad.txt"
NETRC INVALID
)
file(DOWNLOAD
- "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-netrc-bad.txt"
+ "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/netrc-bad.txt"
"${CMAKE_CURRENT_BINARY_DIR}/netrc-bad.txt"
)
diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.txt
index e69de29..e69de29 100644
--- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/netrc-bad.txt
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake b/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake
new file mode 100644
index 0000000..6520940
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-file-arg.cmake
@@ -0,0 +1,11 @@
+include(common.cmake)
+
+set(file "")
+
+file_download()
+
+set(file "${CMAKE_CURRENT_BINARY_DIR}/input.png")
+
+if(NOT EXISTS "${file}")
+ message(FATAL_ERROR "file not downloaded to expected path:\n ${file}")
+endif()
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt
new file mode 100644
index 0000000..701e995
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-file-stdout.txt
@@ -0,0 +1 @@
+-- status='0;"No error"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-file.cmake b/Tests/RunCMake/file-DOWNLOAD/no-file.cmake
new file mode 100644
index 0000000..dc234b2
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-file.cmake
@@ -0,0 +1,11 @@
+include(common.cmake)
+
+# Test downloading without saving to a file.
+set(file "")
+file_download()
+
+foreach(name input.png output.png TIMEOUT)
+ if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${name}")
+ message(FATAL_ERROR "file incorrectly saved to:\n ${CMAKE_CURRENT_BINARY_DIR}/${name}")
+ endif()
+endforeach()
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-stderr.txt
index b0f0d19..8f2f885 100644
--- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash-stderr.txt
@@ -1,4 +1,5 @@
-^CMake Error at DOWNLOAD-no-save-hash\.cmake:[0-9]+ \(file\):
+^CMake Error at common\.cmake:[0-9]+ \(file\):
file DOWNLOAD cannot calculate hash if file is not saved\.
Call Stack \(most recent call first\):
+ no-save-hash.cmake:[0-9]+ \(file_download\)
CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake
new file mode 100644
index 0000000..7fdc397
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.cmake
@@ -0,0 +1,5 @@
+include(common.cmake)
+
+# Test downloading without saving to a file.
+set(file "")
+file_download(EXPECTED_HASH MD5=55555555555555555555555555555555)
diff --git a/Tests/RunCMake/file-DOWNLOAD/no-save-hash.txt b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/no-save-hash.txt
diff --git a/Tests/RunCMake/file-DOWNLOAD/pass-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-stderr.txt
index 2fa2731..23997c5 100644
--- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set-stderr.txt
@@ -1,4 +1,4 @@
-^CMake Error at DOWNLOAD-pass-not-set.cmake:[0-9]+ \(file\):
+^CMake Error at pass-not-set.cmake:[0-9]+ \(file\):
file DOWNLOAD missing string for USERPWD.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/pass-not-set.cmake
index 61eff6d..61eff6d 100644
--- a/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake
+++ b/Tests/RunCMake/file-DOWNLOAD/pass-not-set.cmake
diff --git a/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt b/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt
new file mode 100644
index 0000000..e2ed7aa
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/range-stdout.txt
@@ -0,0 +1,4 @@
+-- status='0;"No error"'
+-- status='0;"No error"'
+-- status='0;"No error"'
+-- status='0;"No error"'
diff --git a/Tests/RunCMake/file-DOWNLOAD/range.cmake b/Tests/RunCMake/file-DOWNLOAD/range.cmake
new file mode 100644
index 0000000..f77bb28
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/range.cmake
@@ -0,0 +1,15 @@
+include(common.cmake)
+
+set(file ${CMAKE_CURRENT_BINARY_DIR}/output1.png)
+file_download(RANGE_START 0 EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92)
+
+set(file ${CMAKE_CURRENT_BINARY_DIR}/output2.png)
+file_download(RANGE_END 50 EXPECTED_MD5 8592e5665b839b5d23825dc84c135b61)
+
+set(file ${CMAKE_CURRENT_BINARY_DIR}/output3.png)
+file_download(RANGE_START 10 RANGE_END 50 EXPECTED_MD5 36cd52681e6c6c8fef85fcd9e86fc30d)
+
+set(file ${CMAKE_CURRENT_BINARY_DIR}/output4.png)
+file_download(RANGE_START 0 RANGE_END 50
+ RANGE_START 60 RANGE_END 100
+ EXPECTED_MD5 c5c9e74e82d493dd901eecccd659cebc)
diff --git a/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-stderr.txt
index 1552baa..d9fa7b7 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set-stderr.txt
@@ -1,4 +1,4 @@
-^CMake Error at DOWNLOAD-tls-cainfo-not-set.cmake:[0-9]+ \(file\):
+^CMake Error at tls-cainfo-not-set.cmake:[0-9]+ \(file\):
file DOWNLOAD missing file value for TLS_CAINFO.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set.cmake
index b476425..b476425 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-cainfo-not-set.cmake
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-cainfo-not-set.cmake
diff --git a/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-result.txt b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-stderr.txt
index 2f46c0c..c048ea9 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set-stderr.txt
@@ -1,4 +1,4 @@
-^CMake Error at DOWNLOAD-tls-verify-not-set.cmake:[0-9]+ \(file\):
+^CMake Error at tls-verify-not-set.cmake:[0-9]+ \(file\):
file DOWNLOAD missing bool value for TLS_VERIFY.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set.cmake
index 919368c..919368c 100644
--- a/Tests/RunCMake/file/DOWNLOAD-tls-verify-not-set.cmake
+++ b/Tests/RunCMake/file-DOWNLOAD/tls-verify-not-set.cmake
diff --git a/Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt b/Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument-result.txt
diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt b/Tests/RunCMake/file-DOWNLOAD/unused-argument-stderr.txt
index 82a78c9..f7cfc4f 100644
--- a/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt
+++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument-stderr.txt
@@ -1,5 +1,6 @@
-^CMake Warning \(dev\) at DOWNLOAD-unused-argument.cmake:[0-9]+ \(file\):
+^CMake Warning \(dev\) at common.cmake:[0-9]+ \(file\):
Unexpected argument: JUNK
Call Stack \(most recent call first\):
+ unused-argument.cmake:[0-9]+ \(file_download\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake b/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake
new file mode 100644
index 0000000..6f7f597
--- /dev/null
+++ b/Tests/RunCMake/file-DOWNLOAD/unused-argument.cmake
@@ -0,0 +1,3 @@
+include(common.cmake)
+
+file_download(JUNK)
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
index 07679b7..43b406b 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
@@ -4,10 +4,8 @@ include(RunCMake)
# Function to build and install a project.
function(run_install_test case)
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(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
# Check "all" components.
set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-all)
@@ -61,8 +59,9 @@ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
set(ENV{LDFLAGS} "${new_ldflags}")
endif()
- if(NOT CMAKE_C_COMPILER_ID MATCHES "^XL")
+ if(NOT CMake_COMPILER_FORCES_NEW_DTAGS)
run_install_test(linux)
+ run_install_test(linux-parent-rpath-propagation)
run_install_test(file-filter)
endif()
run_install_test(linux-unresolved)
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-parent-rpath-propagation.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-parent-rpath-propagation.cmake
new file mode 100644
index 0000000..7e9b7a5
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-parent-rpath-propagation.cmake
@@ -0,0 +1,54 @@
+enable_language(C)
+cmake_policy(SET CMP0095 NEW)
+
+# Force linker to set RPATH instead of RUNPATH
+add_link_options("-Wl,--disable-new-dtags")
+
+# bin/exe (RPATH = "lib1:lib2:lib3")
+# ^
+# |
+# lib1/libone.so (RPATH erased)
+# ^
+# |
+# lib2/libtwo.so (RPATH erased)
+# ^
+# |
+# lib3/libthree.so (RPATH erased)
+# GET_RUNTIME_DEPENDENCIES(bin/exe) should resolve all three libraries
+
+set(TEST_SOURCE_DIR "linux/parent-rpath-propagation")
+
+add_library(three SHARED "${TEST_SOURCE_DIR}/three.c")
+
+add_library(two SHARED "${TEST_SOURCE_DIR}/two.c")
+target_link_libraries(two PUBLIC three)
+
+add_library(one SHARED "${TEST_SOURCE_DIR}/one.c")
+target_link_libraries(one PUBLIC two)
+
+add_executable(exe "${TEST_SOURCE_DIR}/main.c")
+target_link_libraries(exe PUBLIC one)
+
+set_property(TARGET exe PROPERTY INSTALL_RPATH
+ $ORIGIN/../lib1
+ $ORIGIN/../lib2
+ $ORIGIN/../lib3
+)
+
+install(TARGETS exe DESTINATION bin)
+install(TARGETS one DESTINATION lib1)
+install(TARGETS two DESTINATION lib2)
+install(TARGETS three DESTINATION lib3)
+
+install(CODE [[
+ file(GET_RUNTIME_DEPENDENCIES
+ EXECUTABLES
+ "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+ PRE_INCLUDE_REGEXES
+ "^lib(one|two|three)\\.so$"
+ "^libc\\.so"
+ PRE_EXCLUDE_REGEXES ".*"
+ POST_INCLUDE_REGEXES "^.*/lib(one|two|three)\\.so$"
+ POST_EXCLUDE_REGEXES ".*"
+ )
+ ]])
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/main.c b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/main.c
new file mode 100644
index 0000000..12aba5d
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/main.c
@@ -0,0 +1,12 @@
+extern void one(void);
+extern void two(void);
+extern void three(void);
+
+int main(void)
+{
+ one();
+ two();
+ three();
+
+ return 0;
+}
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/one.c b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/one.c
new file mode 100644
index 0000000..9998da8
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/one.c
@@ -0,0 +1,7 @@
+extern void two(void);
+extern void three(void);
+
+void one(void)
+{
+ two();
+}
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/three.c b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/three.c
new file mode 100644
index 0000000..0be5f47
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/three.c
@@ -0,0 +1,3 @@
+void three(void)
+{
+}
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/two.c b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/two.c
new file mode 100644
index 0000000..370baf7
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/two.c
@@ -0,0 +1,6 @@
+extern void three(void);
+
+void two(void)
+{
+ three();
+}
diff --git a/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake b/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake
new file mode 100644
index 0000000..88bf448
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-INPUT_MAY_BE_RECENT.cmake
@@ -0,0 +1,10 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(COPY_FILE "${oldname}" "${newname}" INPUT_MAY_BE_RECENT)
+if(NOT EXISTS "${oldname}")
+ message(FATAL_ERROR "The old name does not exist:\n ${oldname}")
+endif()
+if(NOT EXISTS "${newname}")
+ message(FATAL_ERROR "The new name does not exist:\n ${newname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-input-missing-result.txt b/Tests/RunCMake/file/COPY_FILE-input-missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-input-missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-input-missing-stderr.txt b/Tests/RunCMake/file/COPY_FILE-input-missing-stderr.txt
new file mode 100644
index 0000000..989925d
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-input-missing-stderr.txt
@@ -0,0 +1,14 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-input-missing.cmake:[0-9]+ \(file\):
+ file COPY_FILE failed to copy
+
+ [^
+]*/Tests/RunCMake/file/COPY_FILE-input-missing-build/input-missing
+
+ to
+
+ [^
+]*/Tests/RunCMake/file/COPY_FILE-input-missing-build/output
+
+ because: [^
+]+ \(input\)$
diff --git a/Tests/RunCMake/file/COPY_FILE-input-missing.cmake b/Tests/RunCMake/file/COPY_FILE-input-missing.cmake
new file mode 100644
index 0000000..2d2c55e
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-input-missing.cmake
@@ -0,0 +1,3 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input-missing")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(COPY_FILE "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/COPY_FILE-output-missing-result.txt b/Tests/RunCMake/file/COPY_FILE-output-missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-output-missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-output-missing-stderr.txt b/Tests/RunCMake/file/COPY_FILE-output-missing-stderr.txt
new file mode 100644
index 0000000..0e7d9f7
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-output-missing-stderr.txt
@@ -0,0 +1,14 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-output-missing.cmake:[0-9]+ \(file\):
+ file COPY_FILE failed to copy
+
+ [^
+]*/Tests/RunCMake/file/COPY_FILE-output-missing-build/input
+
+ to
+
+ [^
+]*/Tests/RunCMake/file/COPY_FILE-output-missing-build/output-missing/output
+
+ because: [^
+]+ \(output\)$
diff --git a/Tests/RunCMake/file/COPY_FILE-output-missing.cmake b/Tests/RunCMake/file/COPY_FILE-output-missing.cmake
new file mode 100644
index 0000000..22133e7
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-output-missing.cmake
@@ -0,0 +1,4 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output-missing/output")
+file(WRITE "${oldname}" "")
+file(COPY_FILE "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt b/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt
deleted file mode 100644
index 406e315..0000000
--- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-stderr.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-^CMake Error at DOWNLOAD-hash-mismatch.cmake:[0-9]+ \(file\):
- file DOWNLOAD HASH mismatch
-
- for file: \[.*/Tests/RunCMake/file/DOWNLOAD-hash-mismatch-build/hash-mismatch.txt\]
- expected hash: \[0123456789abcdef0123456789abcdef01234567\]
- actual hash: \[da39a3ee5e6b4b0d3255bfef95601890afd80709\]
- status: \[0;"No error"\]
-
-Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)
-+
-status='1;HASH mismatch: expected: 0123456789abcdef0123456789abcdef01234567 actual: da39a3ee5e6b4b0d3255bfef95601890afd80709'$
diff --git a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake b/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake
deleted file mode 100644
index a91b217..0000000
--- a/Tests/RunCMake/file/DOWNLOAD-hash-mismatch.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
- set(slash /)
-endif()
-file(DOWNLOAD
- "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-hash-mismatch.txt"
- ${CMAKE_CURRENT_BINARY_DIR}/hash-mismatch.txt
- EXPECTED_HASH SHA1=0123456789abcdef0123456789abcdef01234567
- STATUS status
- )
-message("status='${status}'")
diff --git a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake b/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake
deleted file mode 100644
index ce959a7..0000000
--- a/Tests/RunCMake/file/DOWNLOAD-no-save-hash.cmake
+++ /dev/null
@@ -1,8 +0,0 @@
-if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
- set(slash /)
-endif()
-file(DOWNLOAD
- "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-no-save-md5.txt"
- EXPECTED_HASH MD5=55555555555555555555555555555555
- STATUS status
- )
diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake b/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake
deleted file mode 100644
index 2fa5482..0000000
--- a/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake
+++ /dev/null
@@ -1,8 +0,0 @@
-if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" MATCHES "^/")
- set(slash /)
-endif()
-file(DOWNLOAD
- "file://${slash}${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-unused-argument.txt"
- "${CMAKE_CURRENT_BINARY_DIR}/unused-argument.txt"
- JUNK
- )
diff --git a/Tests/RunCMake/file/MAKE_DIRECTORY-fail-result.txt b/Tests/RunCMake/file/MAKE_DIRECTORY-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/MAKE_DIRECTORY-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/MAKE_DIRECTORY-fail-stderr.txt b/Tests/RunCMake/file/MAKE_DIRECTORY-fail-stderr.txt
new file mode 100644
index 0000000..95fccdf
--- /dev/null
+++ b/Tests/RunCMake/file/MAKE_DIRECTORY-fail-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Error at [^
+]*/MAKE_DIRECTORY-fail.cmake:[0-9]+ \(file\):
+ file failed to create directory:
+
+ [^
+]*/Tests/RunCMake/file/MAKE_DIRECTORY-fail-build/file/directory
+
+ because: [^
+]+$
diff --git a/Tests/RunCMake/file/MAKE_DIRECTORY-fail.cmake b/Tests/RunCMake/file/MAKE_DIRECTORY-fail.cmake
new file mode 100644
index 0000000..57a68e5
--- /dev/null
+++ b/Tests/RunCMake/file/MAKE_DIRECTORY-fail.cmake
@@ -0,0 +1,2 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/file" "")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/file/directory")
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index db88956..c75e062 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -4,14 +4,6 @@ run_cmake(CREATE_LINK)
run_cmake(CREATE_LINK-COPY_ON_ERROR)
run_cmake(CREATE_LINK-noarg)
run_cmake(CREATE_LINK-noexist)
-run_cmake(DOWNLOAD-hash-mismatch)
-run_cmake(DOWNLOAD-unused-argument)
-run_cmake(DOWNLOAD-httpheader-not-set)
-run_cmake(DOWNLOAD-netrc-bad)
-run_cmake(DOWNLOAD-tls-cainfo-not-set)
-run_cmake(DOWNLOAD-tls-verify-not-set)
-run_cmake(DOWNLOAD-pass-not-set)
-run_cmake(DOWNLOAD-no-save-hash)
run_cmake(TOUCH)
run_cmake(TOUCH-error-in-source-directory)
run_cmake(TOUCH-error-missing-directory)
@@ -59,12 +51,17 @@ run_cmake_script(COPY_FILE-dirlink-to-file-fail)
run_cmake_script(COPY_FILE-file-to-file)
run_cmake_script(COPY_FILE-file-to-dir-capture)
run_cmake_script(COPY_FILE-file-to-dir-fail)
+run_cmake_script(COPY_FILE-file-INPUT_MAY_BE_RECENT)
run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-capture)
run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-fail)
run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite)
run_cmake_script(COPY_FILE-link-to-file)
run_cmake_script(COPY_FILE-arg-missing)
run_cmake_script(COPY_FILE-arg-unknown)
+run_cmake_script(COPY_FILE-input-missing)
+run_cmake_script(COPY_FILE-output-missing)
+
+run_cmake_script(MAKE_DIRECTORY-fail)
run_cmake_script(RENAME-file-replace)
run_cmake_script(RENAME-file-to-file)
diff --git a/Tests/RunCMake/find_dependency/RunCMakeTest.cmake b/Tests/RunCMake/find_dependency/RunCMakeTest.cmake
index a72d189..6a53133 100644
--- a/Tests/RunCMake/find_dependency/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_dependency/RunCMakeTest.cmake
@@ -3,6 +3,7 @@ include(RunCMake)
# Success tests
run_cmake(realistic)
run_cmake(basic)
+run_cmake(transitive)
# Failure tests
run_cmake(invalid-arg)
diff --git a/Tests/RunCMake/find_dependency/transitive-stdout.txt b/Tests/RunCMake/find_dependency/transitive-stdout.txt
new file mode 100644
index 0000000..6fe40e9
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive-stdout.txt
@@ -0,0 +1,9 @@
+-- begin
+-- Loading E with components: ''
+-- Loading A with components: 'A1'
+-- Loading B with components: 'B1'
+-- Loading A with components: ''
+-- Loading C with components: ''
+-- Loading D with components: ''
+-- Loading B with components: ''
+-- end
diff --git a/Tests/RunCMake/find_dependency/transitive.cmake b/Tests/RunCMake/find_dependency/transitive.cmake
new file mode 100644
index 0000000..5a07f96
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive.cmake
@@ -0,0 +1,3 @@
+message(STATUS "begin")
+find_package(E REQUIRED NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_SOURCE_DIR}/transitive)
+message(STATUS "end")
diff --git a/Tests/RunCMake/find_dependency/transitive/AConfig.cmake b/Tests/RunCMake/find_dependency/transitive/AConfig.cmake
new file mode 100644
index 0000000..b2bf294
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive/AConfig.cmake
@@ -0,0 +1 @@
+message(STATUS "Loading A with components: '${A_FIND_COMPONENTS}'")
diff --git a/Tests/RunCMake/find_dependency/transitive/BConfig.cmake b/Tests/RunCMake/find_dependency/transitive/BConfig.cmake
new file mode 100644
index 0000000..42c2ecd
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive/BConfig.cmake
@@ -0,0 +1,3 @@
+message(STATUS "Loading B with components: '${B_FIND_COMPONENTS}'")
+include(CMakeFindDependencyMacro)
+find_dependency(A NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
diff --git a/Tests/RunCMake/find_dependency/transitive/CConfig.cmake b/Tests/RunCMake/find_dependency/transitive/CConfig.cmake
new file mode 100644
index 0000000..645aedc
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive/CConfig.cmake
@@ -0,0 +1,3 @@
+message(STATUS "Loading C with components: '${C_FIND_COMPONENTS}'")
+include(CMakeFindDependencyMacro)
+find_dependency(A NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
diff --git a/Tests/RunCMake/find_dependency/transitive/DConfig.cmake b/Tests/RunCMake/find_dependency/transitive/DConfig.cmake
new file mode 100644
index 0000000..488c85b
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive/DConfig.cmake
@@ -0,0 +1,5 @@
+message(STATUS "Loading D with components: '${D_FIND_COMPONENTS}'")
+include(CMakeFindDependencyMacro)
+find_dependency(A COMPONENTS A1 NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
+find_dependency(B NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
+find_dependency(C NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
diff --git a/Tests/RunCMake/find_dependency/transitive/EConfig.cmake b/Tests/RunCMake/find_dependency/transitive/EConfig.cmake
new file mode 100644
index 0000000..c8d31de
--- /dev/null
+++ b/Tests/RunCMake/find_dependency/transitive/EConfig.cmake
@@ -0,0 +1,6 @@
+message(STATUS "Loading E with components: '${E_FIND_COMPONENTS}'")
+include(CMakeFindDependencyMacro)
+find_dependency(A COMPONENTS A1 NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
+find_dependency(B COMPONENTS B1 NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
+find_dependency(C NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
+find_dependency(D NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR})
diff --git a/Tests/RunCMake/if/IsDirectoryLong.cmake b/Tests/RunCMake/if/IsDirectoryLong.cmake
index e6939ac..41f1818 100644
--- a/Tests/RunCMake/if/IsDirectoryLong.cmake
+++ b/Tests/RunCMake/if/IsDirectoryLong.cmake
@@ -8,3 +8,6 @@ if(IS_DIRECTORY "${d}/")
else()
message(STATUS "Directory path with length ${dl} correctly does not exist.")
endif()
+if(IS_DIRECTORY "")
+ message(FATAL_ERROR "IS_DIRECTORY \"\" should not exist")
+endif()
diff --git a/Tests/RunCMake/if/RunCMakeTest.cmake b/Tests/RunCMake/if/RunCMakeTest.cmake
index de9cb57..efee116 100644
--- a/Tests/RunCMake/if/RunCMakeTest.cmake
+++ b/Tests/RunCMake/if/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
include(RunCMake)
run_cmake(InvalidArgument1)
+run_cmake(exists)
run_cmake(IsDirectory)
run_cmake(IsDirectoryLong)
run_cmake(duplicate-deep-else)
diff --git a/Tests/RunCMake/if/exists.cmake b/Tests/RunCMake/if/exists.cmake
new file mode 100644
index 0000000..2e5c0ee
--- /dev/null
+++ b/Tests/RunCMake/if/exists.cmake
@@ -0,0 +1,3 @@
+if(EXISTS "")
+ message(FATAL_ERROR "EXISTS \"\" should not exist")
+endif()
diff --git a/Tests/RunCMake/message/ConfigureLog-config.txt b/Tests/RunCMake/message/ConfigureLog-config.txt
new file mode 100644
index 0000000..49c12de
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLog-config.txt
@@ -0,0 +1,30 @@
+^
+---
+events:
+ -
+ kind: "message-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(message\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ message: |
+ Message 0
+ -
+ kind: "message-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(message\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Check 1"
+ message: |
+ Message 1
+ -
+ kind: "message-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(message\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Check 2"
+ - "Check 1"
+ message: |
+ Message 2
+\.\.\.$
diff --git a/Tests/RunCMake/message/ConfigureLog-stdout.txt b/Tests/RunCMake/message/ConfigureLog-stdout.txt
new file mode 100644
index 0000000..ba32642
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLog-stdout.txt
@@ -0,0 +1,4 @@
+-- Check 1
+-- Check 2
+-- Check 2 - passed
+-- Check 1 - passed
diff --git a/Tests/RunCMake/message/ConfigureLog.cmake b/Tests/RunCMake/message/ConfigureLog.cmake
new file mode 100644
index 0000000..6f2c1b0
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLog.cmake
@@ -0,0 +1,7 @@
+message(CONFIGURE_LOG "Message 0")
+message(CHECK_START "Check 1")
+message(CONFIGURE_LOG "Message 1")
+message(CHECK_START "Check 2")
+message(CONFIGURE_LOG "Message 2")
+message(CHECK_PASS "passed")
+message(CHECK_PASS "passed")
diff --git a/Tests/RunCMake/message/ConfigureLogScript-config.txt b/Tests/RunCMake/message/ConfigureLogScript-config.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLogScript-config.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/message/ConfigureLogScript-stdout.txt b/Tests/RunCMake/message/ConfigureLogScript-stdout.txt
new file mode 100644
index 0000000..ba32642
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLogScript-stdout.txt
@@ -0,0 +1,4 @@
+-- Check 1
+-- Check 2
+-- Check 2 - passed
+-- Check 1 - passed
diff --git a/Tests/RunCMake/message/ConfigureLogScript.cmake b/Tests/RunCMake/message/ConfigureLogScript.cmake
new file mode 100644
index 0000000..e1cd21b
--- /dev/null
+++ b/Tests/RunCMake/message/ConfigureLogScript.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/ConfigureLog.cmake")
diff --git a/Tests/RunCMake/message/RunCMakeTest.cmake b/Tests/RunCMake/message/RunCMakeTest.cmake
index 1233838..c54e8f2 100644
--- a/Tests/RunCMake/message/RunCMakeTest.cmake
+++ b/Tests/RunCMake/message/RunCMakeTest.cmake
@@ -1,7 +1,9 @@
include(RunCMake)
+run_cmake_script(ConfigureLogScript)
run_cmake_script(newline)
+run_cmake(ConfigureLog)
run_cmake(defaultmessage)
run_cmake(nomessage)
run_cmake(message-internal-warning)
diff --git a/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt b/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt
index 3a13d32..c11215a 100644
--- a/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt
+++ b/Tests/RunCMake/project/CMP0048-OLD-VERSION-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at CMP0048-OLD-VERSION.cmake:1 \(project\):
VERSION not allowed unless CMP0048 is set to NEW
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project/CMP0048-OLD-stderr.txt b/Tests/RunCMake/project/CMP0048-OLD-stderr.txt
index 1fa70f8..695fb70 100644
--- a/Tests/RunCMake/project/CMP0048-OLD-stderr.txt
+++ b/Tests/RunCMake/project/CMP0048-OLD-stderr.txt
@@ -7,4 +7,4 @@
specific short-term circumstances. Projects should be ported to the NEW
behavior and not rely on setting a policy to OLD.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project/CMP0048-WARN-stderr.txt b/Tests/RunCMake/project/CMP0048-WARN-stderr.txt
index 6d29ad2..d9be5d3 100644
--- a/Tests/RunCMake/project/CMP0048-WARN-stderr.txt
+++ b/Tests/RunCMake/project/CMP0048-WARN-stderr.txt
@@ -8,5 +8,5 @@ CMake Warning \(dev\) at CMP0048-WARN.cmake:3 \(project\):
PROJECT_VERSION
MyProject_VERSION_TWEAK
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/project/CMakeLists.txt b/Tests/RunCMake/project/CMakeLists.txt
index 4b3de84..fdcaee9 100644
--- a/Tests/RunCMake/project/CMakeLists.txt
+++ b/Tests/RunCMake/project/CMakeLists.txt
@@ -1,3 +1,5 @@
-cmake_minimum_required(VERSION 2.8.12)
+if(NOT "x${RunCMake_TEST}" STREQUAL "xNoMinimumRequired")
+ cmake_minimum_required(VERSION 2.8.12)
+endif()
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/project/LanguagesTwice-stderr.txt b/Tests/RunCMake/project/LanguagesTwice-stderr.txt
index 9c69dd0..6edca2f 100644
--- a/Tests/RunCMake/project/LanguagesTwice-stderr.txt
+++ b/Tests/RunCMake/project/LanguagesTwice-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at LanguagesTwice.cmake:1 \(project\):
LANGUAGES may be specified at most once.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project/NoMinimumRequired-stderr.txt b/Tests/RunCMake/project/NoMinimumRequired-stderr.txt
new file mode 100644
index 0000000..83e2ac9
--- /dev/null
+++ b/Tests/RunCMake/project/NoMinimumRequired-stderr.txt
@@ -0,0 +1,5 @@
+CMake Warning \(dev\) at CMakeLists\.txt:[0-9]+ \(project\):
+ cmake_minimum_required\(\) should be called prior to this top-level project\(\)
+ call\. Please see the cmake-commands\(7\) manual for usage documentation of
+ both commands\.
+This warning is for project developers\. Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/project/NoMinimumRequired.cmake b/Tests/RunCMake/project/NoMinimumRequired.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/project/NoMinimumRequired.cmake
diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake
index 6d9f52f..0f3716f 100644
--- a/Tests/RunCMake/project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/project/RunCMakeTest.cmake
@@ -52,3 +52,5 @@ run_cmake(CMP0048-NEW)
run_cmake(CMP0096-WARN)
run_cmake(CMP0096-OLD)
run_cmake(CMP0096-NEW)
+
+run_cmake(NoMinimumRequired)
diff --git a/Tests/RunCMake/project/VersionInvalid-stderr.txt b/Tests/RunCMake/project/VersionInvalid-stderr.txt
index 48358d1..e13a382 100644
--- a/Tests/RunCMake/project/VersionInvalid-stderr.txt
+++ b/Tests/RunCMake/project/VersionInvalid-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at VersionInvalid.cmake:2 \(project\):
VERSION "NONE" format invalid.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt
index 576ac69..63cbf63 100644
--- a/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt
+++ b/Tests/RunCMake/project/VersionMissingLanguages-stderr.txt
@@ -2,4 +2,4 @@ CMake Error at VersionMissingLanguages.cmake:2 \(project\):
project with VERSION, DESCRIPTION or HOMEPAGE_URL must use LANGUAGES before
language names.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project/VersionTwice-stderr.txt b/Tests/RunCMake/project/VersionTwice-stderr.txt
index ec07ead..dc05533 100644
--- a/Tests/RunCMake/project/VersionTwice-stderr.txt
+++ b/Tests/RunCMake/project/VersionTwice-stderr.txt
@@ -1,4 +1,4 @@
CMake Error at VersionTwice.cmake:2 \(project\):
VERSION may be specified at most once.
Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/project_injected/RunCMakeTest.cmake b/Tests/RunCMake/project_injected/RunCMakeTest.cmake
index ba1a003..cf63e12 100644
--- a/Tests/RunCMake/project_injected/RunCMakeTest.cmake
+++ b/Tests/RunCMake/project_injected/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
include(RunCMake)
set(RunCMake_TEST_OPTIONS
+ -DCMAKE_MINIMUM_REQUIRED_VERSION:STATIC=
# Simulate a previous CMake run that used `project(... VERSION ...)`
# in a non-injected call site.
-DCMAKE_PROJECT_VERSION:STATIC=1.2.3
diff --git a/Tests/RunCMake/pseudo_tidy.c b/Tests/RunCMake/pseudo_tidy.c
index a43133b..f227c06 100644
--- a/Tests/RunCMake/pseudo_tidy.c
+++ b/Tests/RunCMake/pseudo_tidy.c
@@ -1,8 +1,13 @@
+#ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
+ FILE* f;
int i;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-p") == 0) {
@@ -20,6 +25,14 @@ int main(int argc, char* argv[])
fprintf(stderr, "stderr from bad command line arg '-bad'\n");
return 1;
}
+ if (strncmp(argv[i], "--export-fixes=", 15) == 0) {
+ f = fopen(argv[i] + 15, "w");
+ if (!f) {
+ fprintf(stderr, "Error opening %s for writing\n", argv[i] + 15);
+ return 1;
+ }
+ fclose(f);
+ }
if (argv[i][0] != '-') {
fprintf(stdout, "%s:0:0: warning: message [checker]\n", argv[i]);
break;
diff --git a/Tests/RunCMake/showIncludes.c b/Tests/RunCMake/showIncludes.c
index 23b3845..4ea2bcc 100644
--- a/Tests/RunCMake/showIncludes.c
+++ b/Tests/RunCMake/showIncludes.c
@@ -1,33 +1,94 @@
+#ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
#if defined(_MSC_VER) && _MSC_VER >= 1928
# pragma warning(disable : 5105) /* macro expansion warning in windows.h */
#endif
#include <windows.h>
#include <stdio.h>
+#include <stdlib.h>
int main()
{
/* 'cl /showIncludes' encodes output in the console output code page. */
unsigned int cp = GetConsoleOutputCP();
+
+ /* 'cl /showIncludes' prints output in the VS language. */
+ const char* vslang = getenv("VSLANG");
+ if (!vslang) {
+ fprintf(stderr, "VSLANG is not set.\n");
+ return 1;
+ }
+
printf("Console output code page: %u\n", cp);
printf("Console input code page: %u\n", GetConsoleCP());
printf("ANSI code page: %u\n", GetACP());
printf("OEM code page: %u\n", GetOEMCP());
+ printf("VSLANG: %s\n", vslang);
+
+ if (strcmp(vslang, "1031") == 0) {
+ if (cp == 437 || cp == 65001) {
+ printf("Hinweis: Einlesen der Datei: C:\\foo.h\n");
+ return 0;
+ }
+ }
- if (cp == 54936 || cp == 936) {
- /* VSLANG=2052 */
- printf("\xd7\xa2\xd2\xe2: "
- "\xb0\xfc\xba\xac\xce\xc4\xbc\xfe:\n");
- return 0;
+ if (strcmp(vslang, "1033") == 0) {
+ if (cp == 437 || cp == 65001) {
+ printf("Note: including file: C:\\foo.h\n");
+ return 0;
+ }
}
- if (cp == 65001) {
- /* VSLANG=2052 */
- printf("\xe6\xb3\xa8\xe6\x84\x8f: "
- "\xe5\x8c\x85\xe5\x90\xab\xe6\x96\x87\xe4\xbb\xb6:\n");
- return 0;
+ if (strcmp(vslang, "1036") == 0) {
+ if (cp == 437 || cp == 863) {
+ printf("Remarque\xff: inclusion du fichier\xff: C:\\foo.h\n");
+ return 0;
+ }
+ if (cp == 65001) {
+ printf("Remarque\xc2\xa0: inclusion du fichier\xc2\xa0: C:\\foo.h\n");
+ return 0;
+ }
+ }
+
+ if (strcmp(vslang, "1040") == 0) {
+ if (cp == 437 || cp == 65001) {
+ printf("Nota: file incluso C:\\foo.h\n");
+ return 0;
+ }
+ }
+
+ if (strcmp(vslang, "1041") == 0) {
+ if (cp == 932) {
+ printf("\x83\x81\x83\x82: "
+ "\x83\x43\x83\x93\x83\x4e\x83\x8b\x81\x5b\x83\x68 "
+ "\x83\x74\x83\x40\x83\x43\x83\x8b: C:\\foo.h\n");
+ return 0;
+ }
+ if (cp == 65001) {
+ printf("\xe3\x83\xa1\xe3\x83\xa2: \xe3\x82\xa4\xe3\x83\xb3"
+ "\xe3\x82\xaf\xe3\x83\xab\xe3\x83\xbc\xe3\x83\x89 "
+ "\xe3\x83\x95\xe3\x82\xa1\xe3\x82\xa4\xe3\x83\xab: C:\\foo.h\n");
+ return 0;
+ }
+ }
+
+ if (strcmp(vslang, "2052") == 0) {
+ if (cp == 54936 || cp == 936) {
+ printf("\xd7\xa2\xd2\xe2: "
+ "\xb0\xfc\xba\xac\xce\xc4\xbc\xfe: C:\\foo.h\n");
+ return 0;
+ }
+
+ if (cp == 65001) {
+ printf("\xe6\xb3\xa8\xe6\x84\x8f: "
+ "\xe5\x8c\x85\xe5\x90\xab\xe6\x96\x87\xe4\xbb\xb6: C:\\foo.h\n");
+ return 0;
+ }
}
- fprintf(stderr, "No example showIncludes for console's output code page.\n");
+ fprintf(stderr, "No example showIncludes for this code page and VSLANG.\n");
return 1;
}
diff --git a/Tests/RunCMake/string/Timestamp-stderr.txt b/Tests/RunCMake/string/Timestamp-stderr.txt
index f162f52..c57bba6 100644
--- a/Tests/RunCMake/string/Timestamp-stderr.txt
+++ b/Tests/RunCMake/string/Timestamp-stderr.txt
@@ -1 +1 @@
-RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789
+^RESULT=2005-08-07 23:19:49.000000 Sunday=Sun August=Aug 05 day=219 wd=0 week=32 w_iso=31 %I=11 epoch=1123456789 TZ=GMT tz=\+0000$
diff --git a/Tests/RunCMake/string/Timestamp.cmake b/Tests/RunCMake/string/Timestamp.cmake
index 531a237..3d68b1a 100644
--- a/Tests/RunCMake/string/Timestamp.cmake
+++ b/Tests/RunCMake/string/Timestamp.cmake
@@ -1,3 +1,3 @@
set(ENV{SOURCE_DATE_EPOCH} "1123456789")
-string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s" UTC)
+string(TIMESTAMP RESULT "%Y-%m-%d %H:%M:%S.%f %A=%a %B=%b %y day=%j wd=%w week=%U w_iso=%V %%I=%I epoch=%s TZ=%Z tz=%z" UTC)
message("RESULT=${RESULT}")
diff --git a/Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake b/Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake
index a419cc9..4dd01db 100644
--- a/Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_compile_definitions/RunCMakeTest.cmake
@@ -2,3 +2,16 @@ include(RunCMake)
run_cmake(empty_keyword_args)
run_cmake(unknown_imported_target)
+
+
+macro(run_cmake_build test)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test} ${CMAKE_COMMAND} --build . --config Release)
+
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+run_cmake(remove_leading_minusD)
+run_cmake_build(remove_leading_minusD)
diff --git a/Tests/RunCMake/target_compile_definitions/foo.c b/Tests/RunCMake/target_compile_definitions/foo.c
new file mode 100644
index 0000000..74a86e1
--- /dev/null
+++ b/Tests/RunCMake/target_compile_definitions/foo.c
@@ -0,0 +1,4 @@
+
+void foo()
+{
+}
diff --git a/Tests/RunCMake/target_compile_definitions/remove_leading_minusD.cmake b/Tests/RunCMake/target_compile_definitions/remove_leading_minusD.cmake
new file mode 100644
index 0000000..53c03c1
--- /dev/null
+++ b/Tests/RunCMake/target_compile_definitions/remove_leading_minusD.cmake
@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(lib1 foo.c)
+target_compile_definitions(lib1 PRIVATE -DDEF0 "$<1:-DDEF1>")
+target_compile_definitions(lib1 PUBLIC -DDEF2 "$<1:-DDEF3>")
+
+add_library(lib2 foo.c)
+target_link_libraries(lib2 PRIVATE lib1)
diff --git a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
index f726759..d703839 100644
--- a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
include(RunCMake)
run_cmake(empty_keyword_args)
+run_cmake(bad_keyword)
if (CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang")
macro(run_cmake_target test subtest target)
diff --git a/Tests/RunCMake/target_compile_options/bad_keyword-result.txt b/Tests/RunCMake/target_compile_options/bad_keyword-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/bad_keyword-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt b/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt
new file mode 100644
index 0000000..e22013e
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/bad_keyword-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error at bad_keyword\.cmake:[0-9]+ \(target_compile_options\):
+ target_compile_options called with invalid arguments
diff --git a/Tests/RunCMake/target_compile_options/bad_keyword.cmake b/Tests/RunCMake/target_compile_options/bad_keyword.cmake
new file mode 100644
index 0000000..b7e6fca
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/bad_keyword.cmake
@@ -0,0 +1,5 @@
+add_library(iface INTERFACE)
+
+# SYSTEM is a recognized keyword for the base class used to implement the
+# command. Verify that we don't allow it.
+target_compile_options(iface SYSTEM PRIVATE)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt
new file mode 100644
index 0000000..07e9a9f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0108-OLD-self-link.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0108 will be removed from a future version
+ of CMake.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake
index 5ade637..1a76e10 100644
--- a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake
+++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake
@@ -1,6 +1,6 @@
enable_language(C)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
add_library(lib1 STATIC empty.c)
target_sources(lib1 PRIVATE FILE_SET UNKNOWN)
diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake
index 332441c..17b37aa 100644
--- a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake
+++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake
@@ -1,6 +1,6 @@
enable_language(C)
-set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
add_library(lib1 STATIC empty.c)
target_sources(lib1 PRIVATE FILE_SET a TYPE UNKNOWN)
diff --git a/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake b/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake
index 72056ae..74795c2 100644
--- a/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake
+++ b/Tests/RunCMake/test_include_dirs/RunCMakeTest.cmake
@@ -1,5 +1,9 @@
include(RunCMake)
+# Isolate our ctest runs from external environment.
+unset(ENV{CTEST_PARALLEL_LEVEL})
+unset(ENV{CTEST_OUTPUT_ON_FAILURE})
+
function(run_TID)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TID-build)
diff --git a/Tests/RunCMake/try_compile/CMP0128-common.cmake b/Tests/RunCMake/try_compile/CMP0128-common.cmake
index 0b8a12b..64b1a77 100644
--- a/Tests/RunCMake/try_compile/CMP0128-common.cmake
+++ b/Tests/RunCMake/try_compile/CMP0128-common.cmake
@@ -1,10 +1,6 @@
cmake_policy(SET CMP0067 NEW)
enable_language(CXX)
-# Isolate the one try_compile below in the error log.
-set(CMakeError_log "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log")
-file(REMOVE "${CMakeError_log}")
-
# Add our own -std= flag to the try_compile check.
set(CMAKE_REQUIRED_FLAGS -std=c++11)
@@ -24,8 +20,21 @@ int main()
}
" SRC_COMPILED)
if(NOT SRC_COMPILED)
- if(EXISTS "${CMakeError_log}")
- file(READ "${CMakeError_log}" err_log)
+ message("Check failed to compile:")
+ set(configure_log "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml")
+ if(EXISTS "${configure_log}")
+ file(READ "${configure_log}" log_content)
+ else()
+ set(log_content "")
+ endif()
+ if(log_content MATCHES [[( -
+ kind: "try_compile-v1"(
++ [^
+]+)+
+ checks:
+ - "Performing Test SRC_COMPILED"(
++ [^
+]+)+)]])
+ message("${configure_log} contains:\n${CMAKE_MATCH_1}")
endif()
- message("${err_log}")
endif()
diff --git a/Tests/RunCMake/try_compile/ConfigureLog-bad.c b/Tests/RunCMake/try_compile/ConfigureLog-bad.c
new file mode 100644
index 0000000..6508ead
--- /dev/null
+++ b/Tests/RunCMake/try_compile/ConfigureLog-bad.c
@@ -0,0 +1 @@
+#error "This does not compile!"
diff --git a/Tests/RunCMake/try_compile/ConfigureLog-config.txt b/Tests/RunCMake/try_compile/ConfigureLog-config.txt
new file mode 100644
index 0000000..ef5c73e
--- /dev/null
+++ b/Tests/RunCMake/try_compile/ConfigureLog-config.txt
@@ -0,0 +1,79 @@
+^
+---
+events:(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)+
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "ConfigureLog.cmake:[0-9]+ \(enable_language\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Detecting C compiler ABI info"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "CMAKE_C_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)*
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_compile\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ description: "Source that should not compile\."
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ: "Upper case"(
+ CMAKE_[^
+]*)+
+ "WITH SPACE": "Space"
+ _-0123456789: "Other chars"
+ abcdefghijklmnopqrstuvwxyz: "Lower case"
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: [1-9][0-9]*
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_compile\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Check 2"
+ - "Check 1"
+ description: "Source that should compile\."
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+\.\.\.$
diff --git a/Tests/RunCMake/try_compile/ConfigureLog-stdout.txt b/Tests/RunCMake/try_compile/ConfigureLog-stdout.txt
new file mode 100644
index 0000000..ba32642
--- /dev/null
+++ b/Tests/RunCMake/try_compile/ConfigureLog-stdout.txt
@@ -0,0 +1,4 @@
+-- Check 1
+-- Check 2
+-- Check 2 - passed
+-- Check 1 - passed
diff --git a/Tests/RunCMake/try_compile/ConfigureLog-test.c b/Tests/RunCMake/try_compile/ConfigureLog-test.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/try_compile/ConfigureLog-test.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/try_compile/ConfigureLog.cmake b/Tests/RunCMake/try_compile/ConfigureLog.cmake
new file mode 100644
index 0000000..a897719
--- /dev/null
+++ b/Tests/RunCMake/try_compile/ConfigureLog.cmake
@@ -0,0 +1,38 @@
+enable_language(C)
+
+set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ abcdefghijklmnopqrstuvwxyz
+ _-0123456789
+ "WITH SPACE"
+ )
+set(ABCDEFGHIJKLMNOPQRSTUVWXYZ "Upper case")
+set(abcdefghijklmnopqrstuvwxyz "Lower case")
+set(_-0123456789 "Other chars")
+set("WITH SPACE" "Space")
+
+try_compile(COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-bad.c
+ LOG_DESCRIPTION "Source that should not compile."
+ )
+
+unset(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES)
+
+try_compile(COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ NO_LOG
+ )
+
+message(CHECK_START "Check 1")
+message(CHECK_START "Check 2")
+try_compile(COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ LOG_DESCRIPTION "Source that should compile."
+ )
+if (COMPILE_RESULT)
+ message(CHECK_PASS "passed")
+ message(CHECK_PASS "passed")
+else()
+ message(CHECK_FAIL "failed")
+ message(CHECK_FAIL "failed")
+endif()
diff --git a/Tests/RunCMake/try_compile/EmptyValueArgs-stderr.txt b/Tests/RunCMake/try_compile/EmptyValueArgs-stderr.txt
index b1344bd..b03e0b3 100644
--- a/Tests/RunCMake/try_compile/EmptyValueArgs-stderr.txt
+++ b/Tests/RunCMake/try_compile/EmptyValueArgs-stderr.txt
@@ -7,3 +7,11 @@ CMake Error at EmptyValueArgs.cmake:[0-9]+ \(try_compile\):
COPY_FILE_ERROR must be followed by a variable name
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Error at EmptyValueArgs.cmake:[0-9]+ \(try_compile\):
+ Error after keyword "LOG_DESCRIPTION":
+
+ empty string not allowed
+
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/try_compile/EmptyValueArgs.cmake b/Tests/RunCMake/try_compile/EmptyValueArgs.cmake
index fda4f10..f0052c5 100644
--- a/Tests/RunCMake/try_compile/EmptyValueArgs.cmake
+++ b/Tests/RunCMake/try_compile/EmptyValueArgs.cmake
@@ -5,3 +5,6 @@ try_compile(RESULT ${try_compile_bindir_or_SOURCES}
try_compile(RESULT ${try_compile_bindir_or_SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/src.c
COPY_FILE "x" COPY_FILE_ERROR "")
+try_compile(RESULT ${try_compile_bindir_or_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+ LOG_DESCRIPTION "")
diff --git a/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt b/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt
index 72e0a01..91dfa6d 100644
--- a/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt
+++ b/Tests/RunCMake/try_compile/ISPCTargets-stderr.txt
@@ -1 +1 @@
-.*Linking ISPC static library*
+(Linking ISPC static library|[ \/]libcmTC_[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\.a|out:([A-Za-z]+[\/])?cmTC_[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\.lib)
diff --git a/Tests/RunCMake/try_compile/Inspect-config.txt b/Tests/RunCMake/try_compile/Inspect-config.txt
new file mode 100644
index 0000000..44bd443
--- /dev/null
+++ b/Tests/RunCMake/try_compile/Inspect-config.txt
@@ -0,0 +1,65 @@
+^
+---
+events:(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)+
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "Inspect.cmake:[0-9]+ \(enable_language\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Detecting C compiler ABI info"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "CMAKE_C_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)+
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCXXCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "Inspect.cmake:[0-9]+ \(enable_language\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Detecting CXX compiler ABI info"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_compile/Inspect-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "CMAKE_CXX_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)*
+\.\.\.$
diff --git a/Tests/RunCMake/try_compile/Inspect.cmake b/Tests/RunCMake/try_compile/Inspect.cmake
index added41..2977d02 100644
--- a/Tests/RunCMake/try_compile/Inspect.cmake
+++ b/Tests/RunCMake/try_compile/Inspect.cmake
@@ -1,4 +1,25 @@
+enable_language(C)
enable_language(CXX)
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "
-set(CMAKE_CXX_EXTENSIONS_DEFAULT \"${CMAKE_CXX_EXTENSIONS_DEFAULT}\")
-")
+if(CMake_TEST_OBJC)
+ enable_language(OBJC)
+ enable_language(OBJCXX)
+endif()
+
+set(info "")
+foreach(var
+ 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_CXX_EXTENSIONS_DEFAULT
+ CMAKE_OBJC_STANDARD_DEFAULT
+ CMAKE_OBJCXX_STANDARD_DEFAULT
+ )
+ if(DEFINED ${var})
+ string(APPEND info "set(${var} \"${${var}}\")\n")
+ endif()
+endforeach()
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")
diff --git a/Tests/RunCMake/try_compile/NoLogDescription-result.txt b/Tests/RunCMake/try_compile/NoLogDescription-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/try_compile/NoLogDescription-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/try_compile/NoLogDescription-stderr.txt b/Tests/RunCMake/try_compile/NoLogDescription-stderr.txt
new file mode 100644
index 0000000..9005bcd
--- /dev/null
+++ b/Tests/RunCMake/try_compile/NoLogDescription-stderr.txt
@@ -0,0 +1,7 @@
+CMake Error at NoLogDescription.cmake:[0-9]+ \(try_compile\):
+ Error after keyword "LOG_DESCRIPTION":
+
+ missing required value
+
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/try_compile/NoLogDescription.cmake b/Tests/RunCMake/try_compile/NoLogDescription.cmake
new file mode 100644
index 0000000..904763f
--- /dev/null
+++ b/Tests/RunCMake/try_compile/NoLogDescription.cmake
@@ -0,0 +1,4 @@
+include(${CMAKE_CURRENT_SOURCE_DIR}/${try_compile_DEFS})
+try_compile(RESULT ${try_compile_bindir_or_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src.c
+ LOG_DESCRIPTION)
diff --git a/Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt b/Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt
index b0438f5..a5ca781 100644
--- a/Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt
+++ b/Tests/RunCMake/try_compile/RerunCMake-rerun-ninja-no-console-stdout.txt
@@ -1,5 +1,5 @@
Running CMake on RerunCMake
FALSE
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: .*/Tests/RunCMake/try_compile/RerunCMake-build
diff --git a/Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt b/Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt
index 9c78b26..e37d210 100644
--- a/Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt
+++ b/Tests/RunCMake/try_compile/RerunCMake-rerun-stdout.txt
@@ -1,3 +1,3 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: .*/Tests/RunCMake/try_compile/RerunCMake-build
diff --git a/Tests/RunCMake/try_compile/RerunCMake-stdout.txt b/Tests/RunCMake/try_compile/RerunCMake-stdout.txt
index 9c78b26..e37d210 100644
--- a/Tests/RunCMake/try_compile/RerunCMake-stdout.txt
+++ b/Tests/RunCMake/try_compile/RerunCMake-stdout.txt
@@ -1,3 +1,3 @@
--- Configuring done
--- Generating done
+-- Configuring done \([0-9]+\.[0-9]s\)
+-- Generating done \([0-9]+\.[0-9]s\)
-- Build files have been written to: .*/Tests/RunCMake/try_compile/RerunCMake-build
diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index 7245471..29c0538 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -1,5 +1,21 @@
include(RunCMake)
+# Detect information from the toolchain:
+# - 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_CXX_EXTENSIONS_DEFAULT
+# - CMAKE_OBJC_STANDARD_DEFAULT
+# - CMAKE_OBJCXX_STANDARD_DEFAULT
+run_cmake_with_options(Inspect
+ -DCMake_TEST_OBJC=${CMake_TEST_OBJC}
+ )
+include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
+
+run_cmake(ConfigureLog)
run_cmake(NoArgs)
run_cmake(OneArg)
run_cmake(TwoArgs)
@@ -29,6 +45,8 @@ run_cmake(ProjectCopyFile)
run_cmake(NonSourceCopyFile)
run_cmake(NonSourceCompileDefinitions)
+run_cmake(Verbose)
+
set(RunCMake_TEST_OPTIONS --debug-trycompile)
run_cmake(PlatformVariables)
run_cmake(WarnDeprecated)
@@ -88,12 +106,6 @@ if(RunCMake_GENERATOR MATCHES "Make|Ninja")
unset(RunCMake_TEST_NO_CLEAN)
endif()
-# Lookup CMAKE_CXX_EXTENSIONS_DEFAULT.
-# FIXME: Someday we could move this to the top of the file and use it in
-# place of some of the values passed by 'Tests/RunCMake/CMakeLists.txt'.
-run_cmake(Inspect)
-include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
-
# FIXME: Support more compilers and default standard levels.
if (DEFINED CMAKE_CXX_STANDARD_DEFAULT AND
DEFINED CMAKE_CXX_EXTENSIONS_DEFAULT AND (
diff --git a/Tests/RunCMake/try_compile/SourceFromBadName-config.txt b/Tests/RunCMake/try_compile/SourceFromBadName-config.txt
new file mode 100644
index 0000000..cb76565
--- /dev/null
+++ b/Tests/RunCMake/try_compile/SourceFromBadName-config.txt
@@ -0,0 +1,11 @@
+^
+---
+events:(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)+
+\.\.\.$
diff --git a/Tests/RunCMake/try_compile/Verbose.c b/Tests/RunCMake/try_compile/Verbose.c
new file mode 100644
index 0000000..5953879
--- /dev/null
+++ b/Tests/RunCMake/try_compile/Verbose.c
@@ -0,0 +1,7 @@
+#ifndef EXAMPLE_DEFINITION
+# error "EXAMPLE_DEFINITION not defined."
+#endif
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/try_compile/Verbose.cmake b/Tests/RunCMake/try_compile/Verbose.cmake
new file mode 100644
index 0000000..3f2a7dd
--- /dev/null
+++ b/Tests/RunCMake/try_compile/Verbose.cmake
@@ -0,0 +1,15 @@
+enable_language(C)
+
+try_compile(COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Verbose.c
+ COMPILE_DEFINITIONS -DEXAMPLE_DEFINITION
+ OUTPUT_VARIABLE out
+ )
+string(REPLACE "\n" "\n " out " ${out}")
+if(NOT COMPILE_RESULT)
+ message(FATAL_ERROR "try_compile failed:\n${out}")
+endif()
+if(NOT out MATCHES "EXAMPLE_DEFINITION"
+ AND NOT CMAKE_GENERATOR MATCHES "NMake|Borland")
+ message(FATAL_ERROR "try_compile output does not contain EXAMPLE_DEFINITION:\n${out}")
+endif()
diff --git a/Tests/RunCMake/try_compile/old_and_new_signature_tests.cmake b/Tests/RunCMake/try_compile/old_and_new_signature_tests.cmake
index 3158e32..0e4cc20 100644
--- a/Tests/RunCMake/try_compile/old_and_new_signature_tests.cmake
+++ b/Tests/RunCMake/try_compile/old_and_new_signature_tests.cmake
@@ -12,6 +12,7 @@ run_cmake(NoCopyFile)
run_cmake(NoCopyFile2)
run_cmake(NoCopyFileError)
run_cmake(NoCStandard)
+run_cmake(NoLogDescription)
run_cmake(NoOutputVariable)
run_cmake(NoOutputVariable2)
run_cmake(BadLinkLibraries)
diff --git a/Tests/RunCMake/try_run/ConfigureLog-bad.c b/Tests/RunCMake/try_run/ConfigureLog-bad.c
new file mode 100644
index 0000000..6508ead
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-bad.c
@@ -0,0 +1 @@
+#error "This does not compile!"
diff --git a/Tests/RunCMake/try_run/ConfigureLog-config.txt b/Tests/RunCMake/try_run/ConfigureLog-config.txt
new file mode 100644
index 0000000..e1d5fa7
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-config.txt
@@ -0,0 +1,134 @@
+^
+---
+events:(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)+
+ -
+ kind: "try_compile-v1"
+ backtrace:
+ - "[^"]*/Modules/CMakeDetermineCompilerABI.cmake:[0-9]+ \(try_compile\)"
+ - "[^"]*/Modules/CMakeTestCCompiler.cmake:[0-9]+ \(CMAKE_DETERMINE_COMPILER_ABI\)"
+ - "CMakeLists.txt:[0-9]+ \(project\)"
+ checks:
+ - "Detecting C compiler ABI info"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "CMAKE_C_ABI_COMPILED"
+ cached: true
+ stdout: \|.*
+ exitCode: 0(
+ -
+ kind: "message-v1"
+ backtrace:(
+ - "[^"]+")+
+ message: \|(
++ [^
+]*)*)*
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ description: "Source that should not compile\."
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: [1-9][0-9]*
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Check 1"
+ description: "Source that should compile\."
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output on stdout!
+ stderr: \|
+ Output, with backslash '\\\\', on stderr!
+ exitCode: 12
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ checks:
+ - "Check 2"
+ - "Check 1"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output, with backslash '\\\\', on stderr!
+ Output on stdout!
+ exitCode: 12
+ -
+ kind: "try_run-v1"
+ backtrace:
+ - "ConfigureLog.cmake:[0-9]+ \(try_run\)"
+ - "CMakeLists.txt:[0-9]+ \(include\)"
+ directories:
+ source: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ binary: "[^"]*/Tests/RunCMake/try_run/ConfigureLog-build/CMakeFiles/CMakeScratch/TryCompile-[^/"]+"
+ cmakeVariables:(
+ CMAKE_[^
+]*)+
+ buildResult:
+ variable: "COMPILE_RESULT"
+ cached: true
+ stdout: \|.*
+ exitCode: 0
+ runResult:
+ variable: "RUN_RESULT"
+ cached: true
+ stdout: \|
+ Output on stdout!
+ stderr: \|
+ Output, with backslash '\\\\', on stderr!
+ exitCode: 12
+\.\.\.$
diff --git a/Tests/RunCMake/try_run/ConfigureLog-stdout.txt b/Tests/RunCMake/try_run/ConfigureLog-stdout.txt
new file mode 100644
index 0000000..ba32642
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-stdout.txt
@@ -0,0 +1,4 @@
+-- Check 1
+-- Check 2
+-- Check 2 - passed
+-- Check 1 - passed
diff --git a/Tests/RunCMake/try_run/ConfigureLog-test.c b/Tests/RunCMake/try_run/ConfigureLog-test.c
new file mode 100644
index 0000000..6a8f125
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog-test.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stderr, "Output, with backslash '\\', on stderr!\n");
+ fflush(stderr); /* make output deterministic even if stderr is buffered */
+ fprintf(stdout, "Output on stdout!\n");
+ return 12;
+}
diff --git a/Tests/RunCMake/try_run/ConfigureLog.cmake b/Tests/RunCMake/try_run/ConfigureLog.cmake
new file mode 100644
index 0000000..6635d73
--- /dev/null
+++ b/Tests/RunCMake/try_run/ConfigureLog.cmake
@@ -0,0 +1,34 @@
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-bad.c
+ LOG_DESCRIPTION "Source that should not compile."
+ )
+
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ NO_LOG
+ )
+
+message(CHECK_START "Check 1")
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ LOG_DESCRIPTION "Source that should compile."
+ )
+
+message(CHECK_START "Check 2")
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ RUN_OUTPUT_VARIABLE RUN_OUTPUT
+ )
+if (RUN_RESULT)
+ message(CHECK_PASS "passed")
+ message(CHECK_PASS "passed")
+else()
+ message(CHECK_FAIL "failed")
+ message(CHECK_FAIL "failed")
+endif()
+
+try_run(RUN_RESULT COMPILE_RESULT
+ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ConfigureLog-test.c
+ RUN_OUTPUT_STDOUT_VARIABLE RUN_STDOUT
+ RUN_OUTPUT_STDERR_VARIABLE RUN_STDERR
+ )
diff --git a/Tests/RunCMake/try_run/RunCMakeTest.cmake b/Tests/RunCMake/try_run/RunCMakeTest.cmake
index dbea089..62e3caf 100644
--- a/Tests/RunCMake/try_run/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_run/RunCMakeTest.cmake
@@ -3,6 +3,7 @@ include(RunCMake)
run_cmake(BinDirEmpty)
run_cmake(BinDirRelative)
run_cmake(NoOutputVariable)
+run_cmake(ConfigureLog)
set(RunCMake_TEST_OPTIONS -Dtry_compile_DEFS=old_signature.cmake)
include(${RunCMake_SOURCE_DIR}/old_and_new_signature_tests.cmake)
diff --git a/Tests/StringFileTest/StringFile.cxx b/Tests/StringFileTest/StringFile.cxx
index c890e8e..073e30c 100644
--- a/Tests/StringFileTest/StringFile.cxx
+++ b/Tests/StringFileTest/StringFile.cxx
@@ -3,7 +3,7 @@
#include "OutputFile.h"
-int main(int, char* [])
+int main(int, char*[])
{
int res = 0;
diff --git a/Tests/SwiftMixLib/CMakeLists.txt b/Tests/SwiftMixLib/CMakeLists.txt
index 40d3498..a52fc94 100644
--- a/Tests/SwiftMixLib/CMakeLists.txt
+++ b/Tests/SwiftMixLib/CMakeLists.txt
@@ -4,3 +4,6 @@ project(SwiftMixLib C CXX Swift)
add_library(SwiftMixedLib lib.c lib.cpp lib.swift)
add_executable(Swifty main.swift)
target_link_libraries(Swifty PUBLIC SwiftMixedLib)
+
+add_executable(c_main main.c)
+target_link_libraries(c_main PUBLIC SwiftMixedLib)
diff --git a/Tests/SwiftMixLib/main.c b/Tests/SwiftMixLib/main.c
new file mode 100644
index 0000000..6ecf984
--- /dev/null
+++ b/Tests/SwiftMixLib/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char* argv[])
+{
+}
diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt
index fa8687d..13cf2b1 100644
--- a/Tests/SwiftOnly/CMakeLists.txt
+++ b/Tests/SwiftOnly/CMakeLists.txt
@@ -43,3 +43,14 @@ target_link_libraries(N PUBLIC
# Dummy to make sure generation works with such targets.
add_library(SwiftIface INTERFACE)
target_link_libraries(SwiftOnly PRIVATE SwiftIface)
+
+# @_alwaysEmitIntoClient ensures that the function body is inserted into the
+# swiftmodule instead of as a symbol in the binary itself. I'm doing this to
+# avoid having to link the executable. There are some flags required in order to
+# link an executable into a library that I didn't see CMake emitting for Swift
+# on macOS. AEIC is the easiest workaround that still tests this functionality.
+# Unfortunately, AEIC was only added recently (~Swift 5.2), so we need to check
+# that it is available before using it.
+if(CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 5.2)
+ add_subdirectory("SwiftPlugin")
+endif()
diff --git a/Tests/SwiftOnly/SwiftPlugin/CMakeLists.txt b/Tests/SwiftOnly/SwiftPlugin/CMakeLists.txt
new file mode 100644
index 0000000..4069f16
--- /dev/null
+++ b/Tests/SwiftOnly/SwiftPlugin/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(main main.swift)
+set_target_properties(main PROPERTIES ENABLE_EXPORTS TRUE)
+
+add_library(plugin plugin.swift)
+target_link_libraries(plugin PRIVATE main)
diff --git a/Tests/SwiftOnly/SwiftPlugin/main.swift b/Tests/SwiftOnly/SwiftPlugin/main.swift
new file mode 100644
index 0000000..f5aac51
--- /dev/null
+++ b/Tests/SwiftOnly/SwiftPlugin/main.swift
@@ -0,0 +1,4 @@
+@_alwaysEmitIntoClient
+public func exported() -> Int { 32 }
+
+print(exported())
diff --git a/Tests/SwiftOnly/SwiftPlugin/plugin.swift b/Tests/SwiftOnly/SwiftPlugin/plugin.swift
new file mode 100644
index 0000000..e84f248
--- /dev/null
+++ b/Tests/SwiftOnly/SwiftPlugin/plugin.swift
@@ -0,0 +1,3 @@
+import main
+
+public func importing() -> Int { main.exported() + 1 }
diff --git a/Tests/SystemInformation/CMakeLists.txt b/Tests/SystemInformation/CMakeLists.txt
index db54612..9a2c4eb 100644
--- a/Tests/SystemInformation/CMakeLists.txt
+++ b/Tests/SystemInformation/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 3.0)
project(SystemInformation)
-include_directories("This does not exists")
+include_directories("This does not exist")
get_directory_property(incl INCLUDE_DIRECTORIES)
set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${SystemInformation_BINARY_DIR};${SystemInformation_SOURCE_DIR}")
diff --git a/Tests/SystemInformation/DumpInformation.cxx b/Tests/SystemInformation/DumpInformation.cxx
index 4328675..913e4c4 100644
--- a/Tests/SystemInformation/DumpInformation.cxx
+++ b/Tests/SystemInformation/DumpInformation.cxx
@@ -53,7 +53,7 @@ void cmDumpInformationPrintFile(const char* name, FILE* fout)
}
}
-int main(int, char* [])
+int main(int, char*[])
{
const char* files[] = {
DumpInformation_BINARY_DIR "/SystemInformation.out",
@@ -63,13 +63,9 @@ int main(int, char* [])
DumpInformation_BINARY_DIR "/OtherProperties.txt",
DumpInformation_BINARY_DIR "/../../Source/cmConfigure.h",
DumpInformation_BINARY_DIR "/../../CMakeCache.txt",
- DumpInformation_BINARY_DIR "/../../CMakeFiles/CMakeOutput.log",
- DumpInformation_BINARY_DIR "/../../CMakeFiles/CMakeError.log",
DumpInformation_BINARY_DIR "/../../Bootstrap.cmk/cmake_bootstrap.log",
DumpInformation_BINARY_DIR "/../../Source/cmsys/Configure.hxx",
DumpInformation_BINARY_DIR "/../../Source/cmsys/Configure.h",
- DumpInformation_BINARY_DIR "/CMakeFiles/CMakeOutput.log",
- DumpInformation_BINARY_DIR "/CMakeFiles/CMakeError.log",
0
};
diff --git a/Tests/UseSWIG/BasicPerl/CMakeLists.txt b/Tests/UseSWIG/BasicPerl/CMakeLists.txt
index 671d529..1151739 100644
--- a/Tests/UseSWIG/BasicPerl/CMakeLists.txt
+++ b/Tests/UseSWIG/BasicPerl/CMakeLists.txt
@@ -4,7 +4,9 @@ project(TestBasicPerl CXX)
include(CTest)
-set(language "perl")
+if(NOT DEFINED language)
+ set(language "perl")
+endif()
include (../BasicConfiguration.cmake)
diff --git a/Tests/UseSWIG/CMakeLists.txt b/Tests/UseSWIG/CMakeLists.txt
index c76e8a0..7c4925e 100644
--- a/Tests/UseSWIG/CMakeLists.txt
+++ b/Tests/UseSWIG/CMakeLists.txt
@@ -20,6 +20,16 @@ add_test(NAME UseSWIG.LegacyPerl COMMAND
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+add_test(NAME UseSWIG.LegacyPerl5 COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/UseSWIG/LegacyPerl"
+ "${CMake_BINARY_DIR}/Tests/UseSWIG/LegacyPerl5"
+ ${build_generator_args}
+ --build-project TestLegacyPerl
+ --build-options ${build_options} -Dlanguage=perl5
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
include(CheckLanguage)
check_language(CSharp)
@@ -66,6 +76,16 @@ add_test(NAME UseSWIG.BasicPerl COMMAND
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+add_test(NAME UseSWIG.BasicPerl5 COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl"
+ "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5"
+ ${build_generator_args}
+ --build-project TestBasicPerl
+ --build-options ${build_options} -Dlanguage=perl5
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2"
AND CMAKE_GENERATOR MATCHES "Make|Ninja|Xcode|Visual Studio (1[1-9]|[2-9][0-9])")
add_test(NAME UseSWIG.Depfile.BasicPython COMMAND
@@ -89,6 +109,16 @@ if(SWIG_FOUND AND NOT SWIG_VERSION VERSION_LESS "4.0.2"
--build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+ add_test(NAME UseSWIG.Depfile.BasicPerl5 COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/UseSWIG/BasicPerl"
+ "${CMake_BINARY_DIR}/Tests/UseSWIG/BasicPerl5.Depfile"
+ ${build_generator_args}
+ --build-project TestBasicPerl
+ --build-options ${build_options} -DSWIG_USE_SWIG_DEPENDENCIES=ON -Dlanguage=perl5
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
endif()
if (CMake_TEST_UseSWIG_Fortran)
diff --git a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
index 90d92f4..be0b465 100644
--- a/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
+++ b/Tests/UseSWIG/LegacyPerl/CMakeLists.txt
@@ -4,7 +4,9 @@ project(TestLegacyPerl CXX)
include(CTest)
-set(language "perl")
+if(NOT DEFINED language)
+ set(language "perl")
+endif()
include (../LegacyConfiguration.cmake)
diff --git a/Tests/VSMARMASM/CMakeLists.txt b/Tests/VSMARMASM/CMakeLists.txt
new file mode 100644
index 0000000..85740de
--- /dev/null
+++ b/Tests/VSMARMASM/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.25) # Enable CMP0141
+project(VSMARMASM C ASM_MARMASM)
+add_executable(VSMARMASM main.c foo.asm)
+target_compile_options(VSMARMASM PRIVATE
+ "$<$<COMPILE_LANGUAGE:ASM_MARMASM>:SHELL:-predefine \"zero SETA 0\">"
+ )
diff --git a/Tests/VSMARMASM/foo.asm b/Tests/VSMARMASM/foo.asm
new file mode 100644
index 0000000..44656ef
--- /dev/null
+++ b/Tests/VSMARMASM/foo.asm
@@ -0,0 +1,10 @@
+ AREA |.text|, CODE
+
+ EXPORT foo
+
+foo PROC
+ mov w0, #zero
+ ret
+ ENDP
+
+ END
diff --git a/Tests/VSMARMASM/main.c b/Tests/VSMARMASM/main.c
new file mode 100644
index 0000000..18ddb78
--- /dev/null
+++ b/Tests/VSMARMASM/main.c
@@ -0,0 +1,5 @@
+extern int foo(void);
+int main(void)
+{
+ return foo();
+}
diff --git a/Tests/VSMASM/CMakeLists.txt b/Tests/VSMASM/CMakeLists.txt
index 603a43b..49bd24a 100644
--- a/Tests/VSMASM/CMakeLists.txt
+++ b/Tests/VSMASM/CMakeLists.txt
@@ -8,3 +8,5 @@ else()
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(VSMASM main.c foo.asm)
+target_compile_definitions(VSMASM PUBLIC DEF_FOO)
+target_compile_options(VSMASM PUBLIC -DDEF_BAR)
diff --git a/Tests/VSMASM/foo.asm b/Tests/VSMASM/foo.asm
index 51cb969..97bdd1a 100644
--- a/Tests/VSMASM/foo.asm
+++ b/Tests/VSMASM/foo.asm
@@ -1,3 +1,9 @@
+ifndef DEF_FOO
+.err <DEF_FOO incorrectly not defined>
+endif
+ifndef DEF_BAR
+.err <DEF_BAR incorrectly not defined>
+endif
ifndef TESTx64
.386
.model flat, c
diff --git a/Tests/VSNASM/CMakeLists.txt b/Tests/VSNASM/CMakeLists.txt
index 821d022..a038ddd 100644
--- a/Tests/VSNASM/CMakeLists.txt
+++ b/Tests/VSNASM/CMakeLists.txt
@@ -18,3 +18,5 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/bar baz.asm" "${BAR_ASM_CONTENTS}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(VSNASM main.c foo.asm "${CMAKE_CURRENT_BINARY_DIR}/bar baz.asm")
+target_compile_definitions(VSNASM PRIVATE DEF_FOO)
+target_compile_options(VSNASM PRIVATE "$<$<COMPILE_LANGUAGE:ASM_NASM>:-t>")
diff --git a/Tests/VSNASM/foo.asm b/Tests/VSNASM/foo.asm
index aba0673..cbfe14b 100644
--- a/Tests/VSNASM/foo.asm
+++ b/Tests/VSNASM/foo.asm
@@ -1,7 +1,11 @@
+%ifndef DEF_FOO
+%error "DEF_FOO incorrectly not defined"
+%endif
section .text
%ifdef TEST2x64
global foo
%else
global _foo
%endif
-%include "foo-proc.asm"
+;TASM compatibility mode allows 'include' instead of '%include'
+include "foo-proc.asm"
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/.gitattributes b/Tests/VSWinStorePhone/Direct3DApp1/.gitattributes
index 78a5469..601c97b 100644
--- a/Tests/VSWinStorePhone/Direct3DApp1/.gitattributes
+++ b/Tests/VSWinStorePhone/Direct3DApp1/.gitattributes
@@ -1 +1 @@
-Direct3DApp1.cpp -format.clang-format-6.0
+Direct3DApp1.cpp -format.clang-format
diff --git a/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h
index 56bd398..ccbbcda 100644
--- a/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h
+++ b/Tests/VSWinStorePhone/Direct3DApp1/BasicTimer.h
@@ -52,13 +52,19 @@ public:
// Update().
property float Total
{
- float get() { return m_total; }
+ float get()
+ {
+ return m_total;
+ }
}
// Duration in seconds between the previous two calls to Update().
property float Delta
{
- float get() { return m_delta; }
+ float get()
+ {
+ return m_delta;
+ }
}
private:
diff --git a/Tests/Wrapping/Wrap.c b/Tests/Wrapping/Wrap.c
index e8fb8a5..30ac173 100644
--- a/Tests/Wrapping/Wrap.c
+++ b/Tests/Wrapping/Wrap.c
@@ -1,7 +1,8 @@
#include <stdio.h>
#ifdef __CLASSIC_C__
-int main(argc, argv) int argc;
+int main(argc, argv)
+int argc;
char** argv;
#else
int main(int argc, const char* argv[])
diff --git a/Utilities/.gitattributes b/Utilities/.gitattributes
index 81bbf26..c43b55d 100644
--- a/Utilities/.gitattributes
+++ b/Utilities/.gitattributes
@@ -3,6 +3,6 @@
SetupForDevelopment.sh export-ignore
# Do not format third-party sources.
-/KWIML/** -format.clang-format-6.0
-/cm*/** -format.clang-format-6.0
-/cmcurl/curltest.c format.clang-format-6.0
+/KWIML/** -format.clang-format
+/cm*/** -format.clang-format
+/cmcurl/curltest.c format.clang-format=15
diff --git a/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt
new file mode 100644
index 0000000..97c176f
--- /dev/null
+++ b/Utilities/ClangTidyModule/CMakeLists.txt
@@ -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.13)
+project(CMakeClangTidyModule C CXX)
+
+get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
+get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Clang REQUIRED)
+
+add_library(cmake-clang-tidy-module MODULE
+ Module.cxx
+
+ OstringstreamUseCmstrcatCheck.cxx
+ OstringstreamUseCmstrcatCheck.h
+ StringConcatenationUseCmstrcatCheck.cxx
+ StringConcatenationUseCmstrcatCheck.h
+ UseBespokeEnumClassCheck.cxx
+ UseBespokeEnumClassCheck.h
+ UseCmstrlenCheck.cxx
+ UseCmstrlenCheck.h
+ UseCmsysFstreamCheck.cxx
+ UseCmsysFstreamCheck.h
+ UsePragmaOnceCheck.cxx
+ UsePragmaOnceCheck.h
+ )
+target_include_directories(cmake-clang-tidy-module PRIVATE ${CLANG_INCLUDE_DIRS})
+target_link_libraries(cmake-clang-tidy-module PRIVATE clang-tidy)
+
+option(RUN_TESTS "Run the tests for the clang-tidy module" OFF)
+if(RUN_TESTS)
+ enable_testing()
+ add_subdirectory(Tests)
+endif()
diff --git a/Utilities/ClangTidyModule/Module.cxx b/Utilities/ClangTidyModule/Module.cxx
new file mode 100644
index 0000000..4dd7dcd
--- /dev/null
+++ b/Utilities/ClangTidyModule/Module.cxx
@@ -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. */
+#include <clang-tidy/ClangTidyModule.h>
+#include <clang-tidy/ClangTidyModuleRegistry.h>
+
+#include "OstringstreamUseCmstrcatCheck.h"
+#include "StringConcatenationUseCmstrcatCheck.h"
+#include "UseBespokeEnumClassCheck.h"
+#include "UseCmstrlenCheck.h"
+#include "UseCmsysFstreamCheck.h"
+#include "UsePragmaOnceCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class CMakeClangTidyModule : public ClangTidyModule
+{
+public:
+ void addCheckFactories(ClangTidyCheckFactories& CheckFactories) override
+ {
+ CheckFactories.registerCheck<UseCmstrlenCheck>("cmake-use-cmstrlen");
+ CheckFactories.registerCheck<UseCmsysFstreamCheck>(
+ "cmake-use-cmsys-fstream");
+ CheckFactories.registerCheck<UseBespokeEnumClassCheck>(
+ "cmake-use-bespoke-enum-class");
+ CheckFactories.registerCheck<OstringstreamUseCmstrcatCheck>(
+ "cmake-ostringstream-use-cmstrcat");
+ CheckFactories.registerCheck<UsePragmaOnceCheck>("cmake-use-pragma-once");
+ CheckFactories.registerCheck<StringConcatenationUseCmstrcatCheck>(
+ "cmake-string-concatenation-use-cmstrcat");
+ }
+};
+
+static ClangTidyModuleRegistry::Add<CMakeClangTidyModule> X(
+ "cmake-clang-tidy", "Adds lint checks for the CMake code base.");
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx
new file mode 100644
index 0000000..920fdf3
--- /dev/null
+++ b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.cxx
@@ -0,0 +1,52 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "OstringstreamUseCmstrcatCheck.h"
+
+#include <clang/AST/Type.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+OstringstreamUseCmstrcatCheck::OstringstreamUseCmstrcatCheck(
+ StringRef Name, ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+{
+}
+
+void OstringstreamUseCmstrcatCheck::registerMatchers(MatchFinder* Finder)
+{
+ Finder->addMatcher(
+ typeLoc(unless(elaboratedTypeLoc()),
+ optionally(hasParent(elaboratedTypeLoc().bind("parentType"))),
+ loc(qualType(
+ hasDeclaration(namedDecl(hasName("::std::ostringstream"))))))
+ .bind("ostringstream"),
+ this);
+}
+
+void OstringstreamUseCmstrcatCheck::check(
+ const MatchFinder::MatchResult& Result)
+{
+ const TypeLoc* ParentTypeNode =
+ Result.Nodes.getNodeAs<TypeLoc>("parentType");
+ const TypeLoc* RootNode = Result.Nodes.getNodeAs<TypeLoc>("ostringstream");
+
+ if (ParentTypeNode != nullptr) {
+ if (ParentTypeNode->getBeginLoc().isValid()) {
+ this->diag(ParentTypeNode->getBeginLoc(),
+ "use strings and cmStrCat() instead of std::ostringstream");
+ }
+
+ } else if (RootNode != nullptr) {
+ if (RootNode->getBeginLoc().isValid()) {
+ this->diag(RootNode->getBeginLoc(),
+ "use strings and cmStrCat() instead of std::ostringstream");
+ }
+ }
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h
new file mode 100644
index 0000000..ecb5616
--- /dev/null
+++ b/Utilities/ClangTidyModule/OstringstreamUseCmstrcatCheck.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class OstringstreamUseCmstrcatCheck : public ClangTidyCheck
+{
+public:
+ OstringstreamUseCmstrcatCheck(StringRef Name, ClangTidyContext* Context);
+ void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+
+ void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.cxx
new file mode 100644
index 0000000..e282d23
--- /dev/null
+++ b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.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 "StringConcatenationUseCmstrcatCheck.h"
+
+#include <cassert>
+
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+#include <clang/Lex/Lexer.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+StringConcatenationUseCmstrcatCheck::StringConcatenationUseCmstrcatCheck(
+ StringRef Name, ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+{
+}
+
+void StringConcatenationUseCmstrcatCheck::registerMatchers(MatchFinder* Finder)
+{
+ auto IsString = expr(hasType(qualType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("::std::basic_string"),
+ hasTemplateArgument(
+ 0, templateArgument(refersToType(asString("char")))))))))));
+
+ auto IsChar = expr(hasType(asString("char")));
+
+ auto IsCharPtr = expr(hasType(pointerType(pointee(asString("const char")))));
+
+ auto IsStringConcat =
+ cxxOperatorCallExpr(hasOperatorName("+"),
+ anyOf(allOf(hasLHS(IsString), hasRHS(IsString)),
+ allOf(hasLHS(IsString), hasRHS(IsChar)),
+ allOf(hasLHS(IsString), hasRHS(IsCharPtr)),
+ allOf(hasLHS(IsChar), hasRHS(IsString)),
+ allOf(hasLHS(IsCharPtr), hasRHS(IsString))));
+
+ auto IsStringAppend = cxxOperatorCallExpr(
+ hasOperatorName("+="), hasLHS(IsString),
+ anyOf(hasRHS(IsString), hasRHS(IsChar), hasRHS(IsCharPtr)));
+
+ auto IsStringConcatWithLHS =
+ cxxOperatorCallExpr(
+ IsStringConcat,
+ optionally(hasLHS(materializeTemporaryExpr(
+ has(cxxBindTemporaryExpr(has(IsStringConcat.bind("lhs"))))))))
+ .bind("concat");
+
+ auto IsStringAppendWithRHS =
+ cxxOperatorCallExpr(
+ IsStringAppend,
+ optionally(hasRHS(materializeTemporaryExpr(has(implicitCastExpr(
+ has(cxxBindTemporaryExpr(has(IsStringConcat.bind("rhs"))))))))))
+ .bind("append");
+
+ Finder->addMatcher(IsStringConcatWithLHS, this);
+ Finder->addMatcher(IsStringAppendWithRHS, this);
+}
+
+void StringConcatenationUseCmstrcatCheck::check(
+ const MatchFinder::MatchResult& Result)
+{
+ const CXXOperatorCallExpr* AppendNode =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("append");
+ const CXXOperatorCallExpr* ConcatNode =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("concat");
+
+ if (AppendNode != nullptr) {
+ if (AppendNode->getBeginLoc().isValid()) {
+ assert(InProgressExprChains.find(AppendNode) ==
+ InProgressExprChains.end());
+
+ ExprChain TmpExprChain =
+ std::make_pair(OperatorType::PlusEquals,
+ std::vector<const CXXOperatorCallExpr*>{ AppendNode });
+ const CXXOperatorCallExpr* RHSNode =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("rhs");
+
+ if (RHSNode != nullptr) {
+ if (RHSNode->getBeginLoc().isValid()) {
+ InProgressExprChains[RHSNode] = std::move(TmpExprChain);
+ }
+ } else {
+ issueCorrection(TmpExprChain, Result);
+ }
+ }
+ }
+
+ if (ConcatNode != nullptr) {
+ if (ConcatNode->getBeginLoc().isValid()) {
+ ExprChain TmpExprChain;
+
+ if (!(InProgressExprChains.find(ConcatNode) ==
+ InProgressExprChains.end())) {
+ TmpExprChain = std::move(InProgressExprChains[ConcatNode]);
+ InProgressExprChains.erase(ConcatNode);
+ if (TmpExprChain.first == OperatorType::PlusEquals) {
+ TmpExprChain.second.insert(TmpExprChain.second.begin() + 1,
+ ConcatNode);
+ } else {
+ TmpExprChain.second.insert(TmpExprChain.second.begin(), ConcatNode);
+ }
+ } else {
+ TmpExprChain = std::make_pair(
+ OperatorType::Plus,
+ std::vector<const CXXOperatorCallExpr*>{ ConcatNode });
+ }
+
+ const CXXOperatorCallExpr* LHSNode =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("lhs");
+
+ if (LHSNode != nullptr) {
+ if (LHSNode->getBeginLoc().isValid()) {
+ InProgressExprChains[LHSNode] = std::move(TmpExprChain);
+ }
+ } else {
+ issueCorrection(TmpExprChain, Result);
+ }
+ }
+ }
+}
+
+void StringConcatenationUseCmstrcatCheck::issueCorrection(
+ const ExprChain& Chain, const MatchFinder::MatchResult& Result)
+{
+ std::vector<FixItHint> FixIts;
+ const CXXOperatorCallExpr* ExprNode;
+ std::vector<const clang::CXXOperatorCallExpr*>::const_iterator It =
+ Chain.second.begin();
+
+ if (Chain.first == OperatorType::PlusEquals) {
+ ExprNode = *It;
+ StringRef LHS = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(ExprNode->getArg(0)->getSourceRange()),
+ Result.Context->getSourceManager(), Result.Context->getLangOpts());
+
+ FixIts.push_back(FixItHint::CreateReplacement(
+ ExprNode->getExprLoc(), "= cmStrCat(" + LHS.str() + ","));
+ It++;
+ } else {
+ ExprNode = *It;
+ FixIts.push_back(
+ FixItHint::CreateInsertion(ExprNode->getBeginLoc(), "cmStrCat("));
+ }
+
+ while (It != std::end(Chain.second)) {
+ ExprNode = *It;
+ FixIts.push_back(
+ FixItHint::CreateReplacement(ExprNode->getOperatorLoc(), ","));
+ It++;
+ }
+ It--;
+ ExprNode = *It;
+
+ StringRef LastToken = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ ExprNode->getArg(1)->getSourceRange().getEnd()),
+ Result.Context->getSourceManager(), Result.Context->getLangOpts());
+ FixIts.push_back(FixItHint::CreateInsertion(
+ ExprNode->getEndLoc().getLocWithOffset(LastToken.str().size()), ")"));
+
+ It = Chain.second.begin();
+ ExprNode = *It;
+
+ if (Chain.first == OperatorType::PlusEquals) {
+ this->diag(ExprNode->getOperatorLoc(),
+ "use cmStrCat() instead of string append")
+ << FixIts;
+ } else {
+ this->diag(ExprNode->getBeginLoc(),
+ "use cmStrCat() instead of string concatenation")
+ << FixIts;
+ }
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.h
new file mode 100644
index 0000000..43ff539
--- /dev/null
+++ b/Utilities/ClangTidyModule/StringConcatenationUseCmstrcatCheck.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 <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class StringConcatenationUseCmstrcatCheck : public ClangTidyCheck
+{
+public:
+ StringConcatenationUseCmstrcatCheck(StringRef Name,
+ ClangTidyContext* Context);
+ void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+
+private:
+ enum class OperatorType
+ {
+ Plus,
+ PlusEquals
+ };
+ typedef std::pair<OperatorType, std::vector<const CXXOperatorCallExpr*>>
+ ExprChain;
+ std::map<const CXXOperatorCallExpr*, ExprChain> InProgressExprChains;
+
+ void issueCorrection(const ExprChain& ExprChain,
+ const ast_matchers::MatchFinder::MatchResult& Result);
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
new file mode 100644
index 0000000..8220f39
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
@@ -0,0 +1,18 @@
+configure_file("${CMake_SOURCE_DIR}/.clang-format" ".clang-format" COPYONLY)
+
+function(add_run_clang_tidy_test check_name)
+ add_test(NAME "RunClangTidy.${check_name}" COMMAND ${CMAKE_COMMAND}
+ "-DCLANG_TIDY_COMMAND=$<TARGET_FILE:clang-tidy>"
+ "-DCLANG_TIDY_MODULE=$<TARGET_FILE:cmake-clang-tidy-module>"
+ "-DCHECK_NAME=${check_name}"
+ "-DRunClangTidy_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/RunClangTidy.cmake"
+ )
+endfunction()
+
+add_run_clang_tidy_test(cmake-use-cmstrlen)
+add_run_clang_tidy_test(cmake-use-cmsys-fstream)
+add_run_clang_tidy_test(cmake-use-bespoke-enum-class)
+add_run_clang_tidy_test(cmake-ostringstream-use-cmstrcat)
+add_run_clang_tidy_test(cmake-use-pragma-once)
+add_run_clang_tidy_test(cmake-string-concatenation-use-cmstrcat)
diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
new file mode 100644
index 0000000..98770d7
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
@@ -0,0 +1,93 @@
+set(config_arg)
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy")
+ set(config_arg "--config-file=${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.clang-tidy")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt")
+ file(READ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-stdout.txt" expect_stdout)
+ string(REGEX REPLACE "\n+$" "" expect_stdout "${expect_stdout}")
+else()
+ set(expect_stdout "")
+endif()
+
+set(source_file "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}.cxx")
+configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx" "${source_file}" COPYONLY)
+
+file(GLOB header_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}" "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/*")
+file(REMOVE_RECURSE "${RunClangTiy_BINARY_DIR}/${CHECK_NAME}")
+foreach(header_file IN LISTS header_files)
+ if(NOT header_file MATCHES "-fixit\\.h\$")
+ file(MAKE_DIRECTORY "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}")
+ configure_file("${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_file}" "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}/${header_file}" COPYONLY)
+ endif()
+endforeach()
+
+set(command
+ "${CLANG_TIDY_COMMAND}"
+ "--load=${CLANG_TIDY_MODULE}"
+ "--checks=-*,${CHECK_NAME}"
+ "--fix"
+ "--format-style=file"
+ "--header-filter=/${CHECK_NAME}/"
+ ${config_arg}
+ "${source_file}"
+ --
+ )
+execute_process(
+ COMMAND ${command}
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE actual_stdout
+ ERROR_VARIABLE actual_stderr
+ )
+string(REPLACE "${RunClangTidy_BINARY_DIR}/" "" actual_stdout "${actual_stdout}")
+
+set(RunClangTidy_TEST_FAILED)
+
+if(NOT result EQUAL 0)
+ string(APPEND RunClangTidy_TEST_FAILED "Expected result: 0, actual result: ${result}\n")
+endif()
+
+string(REGEX REPLACE "\n+$" "" actual_stdout "${actual_stdout}")
+if(NOT actual_stdout STREQUAL expect_stdout)
+ string(REPLACE "\n" "\n " expect_stdout_formatted " ${expect_stdout}")
+ string(REPLACE "\n" "\n " actual_stdout_formatted " ${actual_stdout}")
+ string(APPEND RunClangTidy_TEST_FAILED "Expected stdout:\n${expect_stdout_formatted}\nActual stdout:\n${actual_stdout_formatted}\n")
+endif()
+
+function(check_fixit expected fallback_expected actual)
+ if(EXISTS "${expected}")
+ set(expect_fixit_file "${expected}")
+ else()
+ set(expect_fixit_file "${fallback_expected}")
+ endif()
+ file(READ "${expect_fixit_file}" expect_fixit)
+ file(READ "${actual}" actual_fixit)
+ if(NOT expect_fixit STREQUAL actual_fixit)
+ string(REPLACE "\n" "\n " expect_fixit_formatted " ${expect_fixit}")
+ string(REPLACE "\n" "\n " actual_fixit_formatted " ${actual_fixit}")
+ string(APPEND RunClangTidy_TEST_FAILED "Expected fixit for ${actual}:\n${expect_fixit_formatted}\nActual fixit:\n${actual_fixit_formatted}\n")
+ set(RunClangTidy_TEST_FAILED "${RunClangTidy_TEST_FAILED}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+check_fixit(
+ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx"
+ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx"
+ "${source_file}"
+ )
+
+foreach(header_file IN LISTS header_files)
+ if(NOT header_file MATCHES "-fixit\\.h\$")
+ string(REGEX REPLACE "\\.h\$" "-fixit.h" header_fixit "${header_file}")
+ check_fixit(
+ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_fixit}"
+ "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}/${header_file}"
+ "${RunClangTidy_BINARY_DIR}/${CHECK_NAME}/${header_file}"
+ )
+ endif()
+endforeach()
+
+if(RunClangTidy_TEST_FAILED)
+ string(REPLACE ";" " " command_formatted "${command}")
+ message(FATAL_ERROR "Command:\n ${command_formatted}\n${RunClangTidy_TEST_FAILED}")
+endif()
diff --git a/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt
new file mode 100644
index 0000000..1b2d6e7
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat-stdout.txt
@@ -0,0 +1,6 @@
+cmake-ostringstream-use-cmstrcat.cxx:5:3: warning: use strings and cmStrCat() instead of std::ostringstream [cmake-ostringstream-use-cmstrcat]
+ std::ostringstream test;
+ ^
+cmake-ostringstream-use-cmstrcat.cxx:8:13: warning: use strings and cmStrCat() instead of std::ostringstream [cmake-ostringstream-use-cmstrcat]
+void check2(std::ostringstream& test2)
+ ^
diff --git a/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx
new file mode 100644
index 0000000..ab749a6
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-ostringstream-use-cmstrcat.cxx
@@ -0,0 +1,10 @@
+#include <sstream>
+
+void check()
+{
+ std::ostringstream test;
+}
+
+void check2(std::ostringstream& test2)
+{
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx
new file mode 100644
index 0000000..dd1e6c4
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-fixit.cxx
@@ -0,0 +1,40 @@
+#include <string>
+#include <utility>
+
+template <typename... Args>
+std::string cmStrCat(Args&&... args)
+{
+ return "";
+}
+
+std::string a = "This is a string variable";
+std::string b = " and this is a string variable";
+std::string concat;
+
+// Correction needed
+void test1()
+{
+ concat = cmStrCat(a, b);
+ concat = cmStrCat(a, " and this is a string literal");
+ concat = cmStrCat(a, 'O');
+ concat = cmStrCat("This is a string literal", b);
+ concat = cmStrCat('O', a);
+ concat = cmStrCat(a, " and this is a string literal", 'O', b);
+
+ concat = cmStrCat(concat, b);
+ concat = cmStrCat(concat, " and this is a string literal");
+ concat = cmStrCat(concat, 'o');
+ concat = cmStrCat(concat, b, " and this is a string literal ", 'o', b);
+
+ std::pair<std::string, std::string> p;
+ concat = cmStrCat(p.first, p.second);
+}
+
+// No correction needed
+void test2()
+{
+ a = b;
+ a = "This is a string literal";
+ a = 'X';
+ cmStrCat(a, b);
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt
new file mode 100644
index 0000000..83b8d83
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat-stdout.txt
@@ -0,0 +1,124 @@
+cmake-string-concatenation-use-cmstrcat.cxx:17:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = a + b;
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:17:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:17:14: note: FIX-IT applied suggested code changes
+ concat = a + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:17:17: note: FIX-IT applied suggested code changes
+ concat = a + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:18:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = a + " and this is a string literal";
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:18:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:18:14: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal";
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:18:47: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal";
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:19:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = a + 'O';
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:19:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:19:14: note: FIX-IT applied suggested code changes
+ concat = a + 'O';
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:19:19: note: FIX-IT applied suggested code changes
+ concat = a + 'O';
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:20:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = "This is a string literal" + b;
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:20:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:20:39: note: FIX-IT applied suggested code changes
+ concat = "This is a string literal" + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:20:42: note: FIX-IT applied suggested code changes
+ concat = "This is a string literal" + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:21:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = 'O' + a;
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:21:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:21:16: note: FIX-IT applied suggested code changes
+ concat = 'O' + a;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:21:19: note: FIX-IT applied suggested code changes
+ concat = 'O' + a;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:22:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = a + " and this is a string literal" + 'O' + b;
+ ^ ~ ~ ~
+ cmStrCat( , , , )
+cmake-string-concatenation-use-cmstrcat.cxx:22:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:22:14: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal" + 'O' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:22:48: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal" + 'O' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:22:54: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal" + 'O' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:22:57: note: FIX-IT applied suggested code changes
+ concat = a + " and this is a string literal" + 'O' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:24:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat]
+ concat += b;
+ ^~
+ = cmStrCat(concat, )
+cmake-string-concatenation-use-cmstrcat.cxx:24:10: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:24:14: note: FIX-IT applied suggested code changes
+ concat += b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:25:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat]
+ concat += " and this is a string literal";
+ ^~
+ = cmStrCat(concat, )
+cmake-string-concatenation-use-cmstrcat.cxx:25:10: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:25:44: note: FIX-IT applied suggested code changes
+ concat += " and this is a string literal";
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:26:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat]
+ concat += 'o';
+ ^~
+ = cmStrCat(concat, )
+cmake-string-concatenation-use-cmstrcat.cxx:26:10: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:26:16: note: FIX-IT applied suggested code changes
+ concat += 'o';
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:27:10: warning: use cmStrCat() instead of string append [cmake-string-concatenation-use-cmstrcat]
+ concat += b + " and this is a string literal " + 'o' + b;
+ ^~ ~ ~ ~
+ = cmStrCat(concat, , , , )
+cmake-string-concatenation-use-cmstrcat.cxx:27:10: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:27:15: note: FIX-IT applied suggested code changes
+ concat += b + " and this is a string literal " + 'o' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:27:50: note: FIX-IT applied suggested code changes
+ concat += b + " and this is a string literal " + 'o' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:27:56: note: FIX-IT applied suggested code changes
+ concat += b + " and this is a string literal " + 'o' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:27:59: note: FIX-IT applied suggested code changes
+ concat += b + " and this is a string literal " + 'o' + b;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:30:12: warning: use cmStrCat() instead of string concatenation [cmake-string-concatenation-use-cmstrcat]
+ concat = p.first + p.second;
+ ^ ~
+ cmStrCat( , )
+cmake-string-concatenation-use-cmstrcat.cxx:30:12: note: FIX-IT applied suggested code changes
+cmake-string-concatenation-use-cmstrcat.cxx:30:20: note: FIX-IT applied suggested code changes
+ concat = p.first + p.second;
+ ^
+cmake-string-concatenation-use-cmstrcat.cxx:30:30: note: FIX-IT applied suggested code changes
+ concat = p.first + p.second;
+ ^
diff --git a/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx
new file mode 100644
index 0000000..b088ca3
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-string-concatenation-use-cmstrcat.cxx
@@ -0,0 +1,40 @@
+#include <string>
+#include <utility>
+
+template <typename... Args>
+std::string cmStrCat(Args&&... args)
+{
+ return "";
+}
+
+std::string a = "This is a string variable";
+std::string b = " and this is a string variable";
+std::string concat;
+
+// Correction needed
+void test1()
+{
+ concat = a + b;
+ concat = a + " and this is a string literal";
+ concat = a + 'O';
+ concat = "This is a string literal" + b;
+ concat = 'O' + a;
+ concat = a + " and this is a string literal" + 'O' + b;
+
+ concat += b;
+ concat += " and this is a string literal";
+ concat += 'o';
+ concat += b + " and this is a string literal " + 'o' + b;
+
+ std::pair<std::string, std::string> p;
+ concat = p.first + p.second;
+}
+
+// No correction needed
+void test2()
+{
+ a = b;
+ a = "This is a string literal";
+ a = 'X';
+ cmStrCat(a, b);
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class-stdout.txt
new file mode 100644
index 0000000..5e0acdd
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class-stdout.txt
@@ -0,0 +1,18 @@
+cmake-use-bespoke-enum-class.cxx:3:16: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+bool function1(bool i)
+ ^
+cmake-use-bespoke-enum-class.cxx:8:15: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+int function2(bool i)
+ ^
+cmake-use-bespoke-enum-class.cxx:13:16: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+char function3(bool i)
+ ^
+cmake-use-bespoke-enum-class.cxx:18:16: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+void function4(bool i)
+ ^
+cmake-use-bespoke-enum-class.cxx:22:17: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+float function5(bool i)
+ ^
+cmake-use-bespoke-enum-class.cxx:27:18: warning: use a bespoke enum class instead of booleans as parameters [cmake-use-bespoke-enum-class]
+double function6(bool i)
+ ^
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class.cxx
new file mode 100644
index 0000000..2913e6a
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-bespoke-enum-class.cxx
@@ -0,0 +1,63 @@
+// Correction needed
+
+bool function1(bool i)
+{
+ return true;
+}
+
+int function2(bool i)
+{
+ return 0;
+}
+
+char function3(bool i)
+{
+ return 'a';
+}
+
+void function4(bool i)
+{
+}
+
+float function5(bool i)
+{
+ return 1.0;
+}
+
+double function6(bool i)
+{
+ return 0;
+}
+
+// No correction needed
+bool global;
+
+bool function7(int i)
+{
+ bool l;
+ return true;
+}
+
+int function8(int i)
+{
+ return i;
+}
+
+char function9(char i)
+{
+ return i;
+}
+
+void function10()
+{
+}
+
+float function11(float i)
+{
+ return i;
+}
+
+double function12(double i)
+{
+ return i;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx
new file mode 100644
index 0000000..cde0086
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx
@@ -0,0 +1,42 @@
+#include <cstring>
+
+template <size_t N>
+constexpr size_t cmStrLen(const char (&/*str*/)[N])
+{
+ return N - 1;
+}
+
+namespace ns1 {
+using std::strlen;
+}
+
+namespace ns2 {
+std::size_t strlen(const char* str)
+{
+ return std::strlen(str);
+}
+}
+
+int main()
+{
+ // String variable used for calling strlen() on a variable
+ auto s0 = "howdy";
+
+ // Correction needed
+ (void)cmStrLen("Hello");
+ (void)cmStrLen("Goodbye");
+ (void)cmStrLen("Hola");
+ (void)cmStrLen("Bonjour");
+ (void)(cmStrLen("Hallo"));
+ (void)(4 + cmStrLen("Hallo"));
+ (void)(cmStrLen("Hallo"));
+ (void)(4 + cmStrLen("Hallo"));
+
+ // No correction needed
+ (void)ns2::strlen("Salve");
+ (void)cmStrLen("Konnichiwa");
+ (void)strlen(s0);
+ (void)(sizeof("Hallo") - 2);
+
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt
new file mode 100644
index 0000000..d18822a
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt
@@ -0,0 +1,52 @@
+cmake-use-cmstrlen.cxx:26:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)strlen("Hello");
+ ^~~~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:26:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:27:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)::strlen("Goodbye");
+ ^~~~~~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:27:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:28:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)std::strlen("Hola");
+ ^~~~~~~~~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:28:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:29:9: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)ns1::strlen("Bonjour");
+ ^~~~~~~~~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:29:9: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:30:10: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)(sizeof("Hallo") - 1);
+ ^~~~~~ ~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:30:10: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:30:26: note: FIX-IT applied suggested code changes
+ (void)(sizeof("Hallo") - 1);
+ ^
+cmake-use-cmstrlen.cxx:31:14: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)(4 + sizeof("Hallo") - 1);
+ ^~~~~~ ~~~
+ cmStrLen
+cmake-use-cmstrlen.cxx:31:14: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:31:30: note: FIX-IT applied suggested code changes
+ (void)(4 + sizeof("Hallo") - 1);
+ ^
+cmake-use-cmstrlen.cxx:32:10: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)(sizeof "Hallo" - 1);
+ ^~~~~~ ~~~
+ cmStrLen( )
+cmake-use-cmstrlen.cxx:32:10: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:32:25: note: FIX-IT applied suggested code changes
+ (void)(sizeof "Hallo" - 1);
+ ^
+cmake-use-cmstrlen.cxx:33:14: warning: use cmStrLen() for string literals [cmake-use-cmstrlen]
+ (void)(4 + sizeof "Hallo" - 1);
+ ^~~~~~ ~~~
+ cmStrLen( )
+cmake-use-cmstrlen.cxx:33:14: note: FIX-IT applied suggested code changes
+cmake-use-cmstrlen.cxx:33:29: note: FIX-IT applied suggested code changes
+ (void)(4 + sizeof "Hallo" - 1);
+ ^
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
new file mode 100644
index 0000000..205bc9c
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
@@ -0,0 +1,42 @@
+#include <cstring>
+
+template <size_t N>
+constexpr size_t cmStrLen(const char (&/*str*/)[N])
+{
+ return N - 1;
+}
+
+namespace ns1 {
+using std::strlen;
+}
+
+namespace ns2 {
+std::size_t strlen(const char* str)
+{
+ return std::strlen(str);
+}
+}
+
+int main()
+{
+ // String variable used for calling strlen() on a variable
+ auto s0 = "howdy";
+
+ // Correction needed
+ (void)strlen("Hello");
+ (void)::strlen("Goodbye");
+ (void)std::strlen("Hola");
+ (void)ns1::strlen("Bonjour");
+ (void)(sizeof("Hallo") - 1);
+ (void)(4 + sizeof("Hallo") - 1);
+ (void)(sizeof "Hallo" - 1);
+ (void)(4 + sizeof "Hallo" - 1);
+
+ // No correction needed
+ (void)ns2::strlen("Salve");
+ (void)cmStrLen("Konnichiwa");
+ (void)strlen(s0);
+ (void)(sizeof("Hallo") - 2);
+
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx
new file mode 100644
index 0000000..5c7c123
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-fixit.cxx
@@ -0,0 +1,81 @@
+#include <fstream>
+#include <vector>
+
+namespace cmsys {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+class cl
+{
+public:
+ using ifstream = cmsys::ifstream;
+ using ofstream = cmsys::ofstream;
+ using fstream = cmsys::fstream;
+};
+
+using ifs = cmsys::ifstream;
+using ofs = cmsys::ofstream;
+using fs = cmsys::fstream;
+}
+
+int main()
+{
+ using std::ifstream;
+ using std::ofstream;
+ using std::fstream;
+
+ // Correction needed
+ cmsys::ifstream ifsUnqual;
+ cmsys::ifstream ifsQual;
+ cmsys::ifstream ifsNS;
+ cmsys::ifstream ifsNested;
+ cmsys::ifstream ifsClass;
+ cmsys::ifstream ifsRenamed;
+
+ cmsys::ofstream ofsUnqual;
+ cmsys::ofstream ofsQual;
+ cmsys::ofstream ofsNS;
+ cmsys::ofstream ofsNested;
+ cmsys::ofstream ofsClass;
+ cmsys::ofstream ofsRenamed;
+
+ cmsys::fstream fsUnqual;
+ cmsys::fstream fsQual;
+ cmsys::fstream fsNS;
+ cmsys::fstream fsNested;
+ cmsys::fstream fsClass;
+ cmsys::fstream fsRenamed;
+
+ cmsys::ifstream::off_type offsetQual = 0;
+ cmsys::ifstream::off_type offsetUnqual = 0;
+ cmsys::ifstream::off_type offsetNS = 0;
+ cmsys::ifstream::off_type offsetNested = 0;
+ cmsys::ifstream::traits_type::off_type offsetTraitsNested = 0;
+ cmsys::ifstream::traits_type::off_type offsetTraitsClass = 0;
+
+ std::vector<cmsys::ifstream> ifsVectorUnqual;
+
+ // No correction needed
+ cmsys::ifstream ifsCmsys;
+ cmsys::ofstream ofsCmsys;
+ cmsys::fstream fsCmsys;
+ cmsys::ifstream::off_type offsetCmsys = 0;
+ cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0;
+ std::vector<cmsys::ifstream> ifsVectorCmsys;
+ std::basic_ifstream<wchar_t> ifsWchar;
+
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt
new file mode 100644
index 0000000..d2c45f2
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream-stdout.txt
@@ -0,0 +1,155 @@
+cmake-use-cmsys-fstream.cxx:24:20: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ using ifstream = std::ifstream;
+ ^~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:24:20: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:25:20: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ using ofstream = std::ofstream;
+ ^~~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:25:20: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:26:19: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ using fstream = std::fstream;
+ ^~~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:26:19: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:29:13: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+using ifs = std::ifstream;
+ ^~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:29:13: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:30:13: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+using ofs = std::ofstream;
+ ^~~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:30:13: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:31:12: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+using fs = std::fstream;
+ ^~~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:31:12: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:41:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ifstream ifsUnqual;
+ ^~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:41:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:42:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ std::ifstream ifsQual;
+ ^~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:42:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:43:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ifstream ifsNS;
+ ^~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:43:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:44:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ns::ifstream ifsNested;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:44:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:45:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::cl::ifstream ifsClass;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:45:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:46:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ifs ifsRenamed;
+ ^~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:46:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:48:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ ofstream ofsUnqual;
+ ^~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:48:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:49:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ std::ofstream ofsQual;
+ ^~~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:49:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:50:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ ns::ofstream ofsNS;
+ ^~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:50:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:51:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ ns::ns::ofstream ofsNested;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:51:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:52:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ ns::cl::ofstream ofsClass;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:52:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:53:3: warning: use cmsys::ofstream [cmake-use-cmsys-fstream]
+ ns::ofs ofsRenamed;
+ ^~~~~~~
+ cmsys::ofstream
+cmake-use-cmsys-fstream.cxx:53:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:55:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ fstream fsUnqual;
+ ^~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:55:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:56:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ std::fstream fsQual;
+ ^~~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:56:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:57:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ ns::fstream fsNS;
+ ^~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:57:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:58:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ ns::ns::fstream fsNested;
+ ^~~~~~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:58:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:59:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ ns::ns::fstream fsClass;
+ ^~~~~~~~~~~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:59:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:60:3: warning: use cmsys::fstream [cmake-use-cmsys-fstream]
+ ns::fs fsRenamed;
+ ^~~~~~
+ cmsys::fstream
+cmake-use-cmsys-fstream.cxx:60:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:62:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ std::ifstream::off_type offsetQual = 0;
+ ^~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:62:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:63:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ifstream::off_type offsetUnqual = 0;
+ ^~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:63:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:64:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ifstream::off_type offsetNS = 0;
+ ^~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:64:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:65:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ns::ifstream::off_type offsetNested = 0;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:65:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:66:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:66:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:67:3: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0;
+ ^~~~~~~~~~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:67:3: note: FIX-IT applied suggested code changes
+cmake-use-cmsys-fstream.cxx:69:15: warning: use cmsys::ifstream [cmake-use-cmsys-fstream]
+ std::vector<ifstream> ifsVectorUnqual;
+ ^~~~~~~~
+ cmsys::ifstream
+cmake-use-cmsys-fstream.cxx:69:15: note: FIX-IT applied suggested code changes
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx
new file mode 100644
index 0000000..56a7611
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmsys-fstream.cxx
@@ -0,0 +1,81 @@
+#include <fstream>
+#include <vector>
+
+namespace cmsys {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+
+namespace ns {
+using std::ifstream;
+using std::ofstream;
+using std::fstream;
+}
+
+class cl
+{
+public:
+ using ifstream = std::ifstream;
+ using ofstream = std::ofstream;
+ using fstream = std::fstream;
+};
+
+using ifs = std::ifstream;
+using ofs = std::ofstream;
+using fs = std::fstream;
+}
+
+int main()
+{
+ using std::ifstream;
+ using std::ofstream;
+ using std::fstream;
+
+ // Correction needed
+ ifstream ifsUnqual;
+ std::ifstream ifsQual;
+ ns::ifstream ifsNS;
+ ns::ns::ifstream ifsNested;
+ ns::cl::ifstream ifsClass;
+ ns::ifs ifsRenamed;
+
+ ofstream ofsUnqual;
+ std::ofstream ofsQual;
+ ns::ofstream ofsNS;
+ ns::ns::ofstream ofsNested;
+ ns::cl::ofstream ofsClass;
+ ns::ofs ofsRenamed;
+
+ fstream fsUnqual;
+ std::fstream fsQual;
+ ns::fstream fsNS;
+ ns::ns::fstream fsNested;
+ ns::ns::fstream fsClass;
+ ns::fs fsRenamed;
+
+ std::ifstream::off_type offsetQual = 0;
+ ifstream::off_type offsetUnqual = 0;
+ ns::ifstream::off_type offsetNS = 0;
+ ns::ns::ifstream::off_type offsetNested = 0;
+ ns::ns::ifstream::traits_type::off_type offsetTraitsNested = 0;
+ ns::cl::ifstream::traits_type::off_type offsetTraitsClass = 0;
+
+ std::vector<ifstream> ifsVectorUnqual;
+
+ // No correction needed
+ cmsys::ifstream ifsCmsys;
+ cmsys::ofstream ofsCmsys;
+ cmsys::fstream fsCmsys;
+ cmsys::ifstream::off_type offsetCmsys = 0;
+ cmsys::ifstream::traits_type::off_type offsetTraitsCmsys = 0;
+ std::vector<cmsys::ifstream> ifsVectorCmsys;
+ std::basic_ifstream<wchar_t> ifsWchar;
+
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt
new file mode 100644
index 0000000..e80e4a4
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once-stdout.txt
@@ -0,0 +1,25 @@
+cmake-use-pragma-once/cmake-use-pragma-once-both.h:1:1: warning: use #pragma once [cmake-use-pragma-once]
+#ifndef BOTH_H
+^~~~~~~~~~~~~~
+cmake-use-pragma-once/cmake-use-pragma-once-both.h:1:1: note: FIX-IT applied suggested code changes
+cmake-use-pragma-once/cmake-use-pragma-once-both.h:2:1: note: FIX-IT applied suggested code changes
+#define BOTH_H
+^
+cmake-use-pragma-once/cmake-use-pragma-once-both.h:10:1: note: FIX-IT applied suggested code changes
+#endif
+^
+cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:1:1: warning: use #pragma once [cmake-use-pragma-once]
+#ifndef INCLUDE_GUARDS_H
+^~~~~~~~~~~~~~~~~~~~~~~~
+#pragma once
+cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:1:1: note: FIX-IT applied suggested code changes
+cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:2:1: note: FIX-IT applied suggested code changes
+#define INCLUDE_GUARDS_H
+^
+cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h:9:1: note: FIX-IT applied suggested code changes
+#endif
+^
+cmake-use-pragma-once/cmake-use-pragma-once-neither.h:1:1: warning: use #pragma once [cmake-use-pragma-once]
+int neither()
+^
+cmake-use-pragma-once/cmake-use-pragma-once-neither.h:1:1: note: FIX-IT applied suggested code changes
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx
new file mode 100644
index 0000000..a571bc1
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once.cxx
@@ -0,0 +1,5 @@
+#include "cmake-use-pragma-once/cmake-use-pragma-once.h"
+
+#include "cmake-use-pragma-once/cmake-use-pragma-once-both.h"
+#include "cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h"
+#include "cmake-use-pragma-once/cmake-use-pragma-once-neither.h"
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h
new file mode 100644
index 0000000..73c9720
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both-fixit.h
@@ -0,0 +1,8 @@
+
+
+#pragma once
+
+int both()
+{
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h
new file mode 100644
index 0000000..fdf3cd3
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-both.h
@@ -0,0 +1,10 @@
+#ifndef BOTH_H
+#define BOTH_H
+#pragma once
+
+int both()
+{
+ return 0;
+}
+
+#endif
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h
new file mode 100644
index 0000000..36461c2
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards-fixit.h
@@ -0,0 +1,6 @@
+#pragma once
+
+int includeGuards()
+{
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h
new file mode 100644
index 0000000..687306d
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-include-guards.h
@@ -0,0 +1,9 @@
+#ifndef INCLUDE_GUARDS_H
+#define INCLUDE_GUARDS_H
+
+int includeGuards()
+{
+ return 0;
+}
+
+#endif
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h
new file mode 100644
index 0000000..eb5c6dd
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither-fixit.h
@@ -0,0 +1,5 @@
+#pragma once
+int neither()
+{
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h
new file mode 100644
index 0000000..c779ca0
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once-neither.h
@@ -0,0 +1,4 @@
+int neither()
+{
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h
new file mode 100644
index 0000000..b0b2ea2
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-pragma-once/cmake-use-pragma-once.h
@@ -0,0 +1,6 @@
+#pragma once
+
+int once()
+{
+ return 0;
+}
diff --git a/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.cxx b/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.cxx
new file mode 100644
index 0000000..26f3749
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.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 "UseBespokeEnumClassCheck.h"
+
+#include <clang/AST/Type.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+UseBespokeEnumClassCheck::UseBespokeEnumClassCheck(StringRef Name,
+ ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+{
+}
+
+void UseBespokeEnumClassCheck::registerMatchers(MatchFinder* Finder)
+{
+ Finder->addMatcher(
+ parmVarDecl(
+ hasTypeLoc(typeLoc(loc(qualType(asString("_Bool")))).bind("type"))),
+ this);
+}
+
+void UseBespokeEnumClassCheck::check(const MatchFinder::MatchResult& Result)
+{
+ const TypeLoc* Node = Result.Nodes.getNodeAs<TypeLoc>("type");
+ this->diag(Node->getBeginLoc(),
+ "use a bespoke enum class instead of booleans as parameters");
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.h b/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.h
new file mode 100644
index 0000000..be76db0
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseBespokeEnumClassCheck.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class UseBespokeEnumClassCheck : public ClangTidyCheck
+{
+public:
+ UseBespokeEnumClassCheck(StringRef Name, ClangTidyContext* Context);
+ void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+
+ void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx
new file mode 100644
index 0000000..d4bae1f
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.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 "UseCmstrlenCheck.h"
+
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+UseCmstrlenCheck::UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+{
+}
+
+void UseCmstrlenCheck::registerMatchers(MatchFinder* Finder)
+{
+ Finder->addMatcher(callExpr(callee(functionDecl(hasName("::strlen"))),
+ callee(expr().bind("strlen")),
+ hasArgument(0, stringLiteral())),
+ this);
+
+ auto IsSizeOfStringLiteral =
+ unaryExprOrTypeTraitExpr(
+ ofKind(UETT_SizeOf),
+ anyOf(has(parenExpr(has(stringLiteral())).bind("paren")),
+ has(stringLiteral())))
+ .bind("sizeOf");
+ Finder->addMatcher(
+ binaryOperator(
+ hasOperatorName("-"),
+ hasLHS(anyOf(
+ binaryOperator(hasOperatorName("+"), hasRHS(IsSizeOfStringLiteral)),
+ IsSizeOfStringLiteral)),
+ hasRHS(implicitCastExpr(has(integerLiteral(equals(1)).bind("literal")))))
+ .bind("sizeOfMinus"),
+ this);
+}
+
+void UseCmstrlenCheck::check(const MatchFinder::MatchResult& Result)
+{
+ const Expr* Strlen = Result.Nodes.getNodeAs<Expr>("strlen");
+ const BinaryOperator* SizeOfMinus =
+ Result.Nodes.getNodeAs<BinaryOperator>("sizeOfMinus");
+
+ if (Strlen) {
+ this->diag(Strlen->getBeginLoc(), "use cmStrLen() for string literals")
+ << FixItHint::CreateReplacement(Strlen->getSourceRange(), "cmStrLen");
+ }
+
+ if (SizeOfMinus) {
+ const ParenExpr* Paren = Result.Nodes.getNodeAs<ParenExpr>("paren");
+ const UnaryExprOrTypeTraitExpr* SizeOf =
+ Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeOf");
+ const IntegerLiteral* Literal =
+ Result.Nodes.getNodeAs<IntegerLiteral>("literal");
+
+ std::vector<FixItHint> FixIts;
+ if (Paren) {
+ FixIts.push_back(
+ FixItHint::CreateReplacement(SizeOf->getOperatorLoc(), "cmStrLen"));
+ FixIts.push_back(FixItHint::CreateRemoval(
+ SourceRange(SizeOfMinus->getOperatorLoc(), Literal->getLocation())));
+ } else {
+ FixIts.push_back(
+ FixItHint::CreateReplacement(SizeOf->getOperatorLoc(), "cmStrLen("));
+ FixIts.push_back(FixItHint::CreateReplacement(
+ SourceRange(SizeOfMinus->getOperatorLoc(), Literal->getLocation()),
+ ")"));
+ }
+ this->diag(SizeOf->getOperatorLoc(), "use cmStrLen() for string literals")
+ << FixIts;
+ }
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmstrlenCheck.h b/Utilities/ClangTidyModule/UseCmstrlenCheck.h
new file mode 100644
index 0000000..08f77c2
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class UseCmstrlenCheck : public ClangTidyCheck
+{
+public:
+ UseCmstrlenCheck(StringRef Name, ClangTidyContext* Context);
+ void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+
+ void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.cxx
new file mode 100644
index 0000000..95a0a4d
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.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 "UseCmsysFstreamCheck.h"
+
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+using namespace ast_matchers;
+
+UseCmsysFstreamCheck::UseCmsysFstreamCheck(StringRef Name,
+ ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+{
+}
+
+void UseCmsysFstreamCheck::registerMatchers(MatchFinder* Finder)
+{
+ this->createMatcher("::std::basic_ifstream", "::cmsys::ifstream", Finder,
+ "ifstream");
+ this->createMatcher("::std::basic_ofstream", "::cmsys::ofstream", Finder,
+ "ofstream");
+ this->createMatcher("::std::basic_fstream", "::cmsys::fstream", Finder,
+ "fstream");
+}
+
+void UseCmsysFstreamCheck::check(const MatchFinder::MatchResult& Result)
+{
+ const TypeLoc* ParentTypeNode =
+ Result.Nodes.getNodeAs<TypeLoc>("parentType");
+ const NestedNameSpecifierLoc* ParentNameNode =
+ Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("parentName");
+ const TypeLoc* RootNode = nullptr;
+ StringRef BindName;
+ StringRef Warning;
+
+ if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ifstream")) != nullptr) {
+ BindName = "cmsys::ifstream";
+ Warning = "use cmsys::ifstream";
+ } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("ofstream")) !=
+ nullptr) {
+ BindName = "cmsys::ofstream";
+ Warning = "use cmsys::ofstream";
+ } else if ((RootNode = Result.Nodes.getNodeAs<TypeLoc>("fstream")) !=
+ nullptr) {
+ BindName = "cmsys::fstream";
+ Warning = "use cmsys::fstream";
+ }
+
+ if (ParentTypeNode != nullptr) {
+ if (ParentTypeNode->getBeginLoc().isValid()) {
+ this->diag(ParentTypeNode->getBeginLoc(), Warning)
+ << FixItHint::CreateReplacement(ParentTypeNode->getSourceRange(),
+ BindName);
+ }
+ } else if (ParentNameNode != nullptr) {
+ if (ParentNameNode->getBeginLoc().isValid()) {
+ this->diag(ParentNameNode->getBeginLoc(), Warning)
+ << FixItHint::CreateReplacement(
+ SourceRange(ParentNameNode->getBeginLoc(), RootNode->getEndLoc()),
+ BindName);
+ }
+ } else if (RootNode != nullptr) {
+ if (RootNode->getBeginLoc().isValid()) {
+ this->diag(RootNode->getBeginLoc(), Warning)
+ << FixItHint::CreateReplacement(RootNode->getSourceRange(), BindName);
+ }
+ }
+}
+
+void UseCmsysFstreamCheck::createMatcher(StringRef StdName,
+ StringRef CmsysName,
+ ast_matchers::MatchFinder* Finder,
+ StringRef Bind)
+{
+ TypeLocMatcher IsStd = loc(qualType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(classTemplateSpecializationDecl(
+ hasName(StdName),
+ hasTemplateArgument(
+ 0, templateArgument(refersToType(asString("char"))))))))));
+
+ // TODO This only checks to see if the type directly refers to
+ // cmsys::fstream. There are some corner cases involving template parameters
+ // that refer to cmsys::fstream that are missed by this matcher, resulting in
+ // a false positive. Figure out how to find these indirect references to
+ // cmsys::fstream and filter them out. In the meantime, such false positives
+ // can be silenced with NOLINT(cmake-use-cmsys-fstream).
+ TypeLocMatcher IsCmsys =
+ loc(usingType(throughUsingDecl(namedDecl(hasName(CmsysName)))));
+
+ Finder->addMatcher(
+ typeLoc(IsStd, unless(IsCmsys), unless(elaboratedTypeLoc()),
+ optionally(hasParent(elaboratedTypeLoc().bind("parentType"))),
+ optionally(hasParent(nestedNameSpecifierLoc().bind("parentName"))))
+ .bind(Bind),
+ this);
+}
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.h
new file mode 100644
index 0000000..782123c
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmsysFstreamCheck.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 <clang-tidy/ClangTidyCheck.h>
+#include <clang/ASTMatchers/ASTMatchFinder.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+class UseCmsysFstreamCheck : public ClangTidyCheck
+{
+public:
+ UseCmsysFstreamCheck(StringRef Name, ClangTidyContext* Context);
+ void registerMatchers(ast_matchers::MatchFinder* Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult& Result) override;
+
+private:
+ void createMatcher(StringRef name, StringRef CmsysName,
+ ast_matchers::MatchFinder* Finder, StringRef bind);
+};
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx b/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx
new file mode 100644
index 0000000..7a42798
--- /dev/null
+++ b/Utilities/ClangTidyModule/UsePragmaOnceCheck.cxx
@@ -0,0 +1,325 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+/* This code was originally taken from part of the Clang-Tidy LLVM project and
+ * modified for use with CMake under the following original license: */
+
+//===--- HeaderGuard.cpp - clang-tidy
+//-------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions. See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UsePragmaOnceCheck.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Lex/PPCallbacks.h>
+#include <clang/Lex/Preprocessor.h>
+#include <clang/Tooling/Tooling.h>
+#include <llvm/Support/Path.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+
+/// canonicalize a path by removing ./ and ../ components.
+static std::string cleanPath(StringRef Path)
+{
+ SmallString<256> Result = Path;
+ llvm::sys::path::remove_dots(Result, true);
+ return std::string(Result.str());
+}
+
+namespace {
+// This class is a workaround for the fact that PPCallbacks doesn't give us the
+// location of the hash for an #ifndef, #define, or #endif, so we have to find
+// it ourselves. We can't lex backwards, and attempting to turn on the
+// preprocessor's backtracking functionality wreaks havoc, so we have to
+// instantiate a second lexer and lex all the way from the beginning of the
+// file. Cache the results of this lexing so that we don't have to do it more
+// times than needed.
+//
+// TODO: Upstream a change to LLVM to give us the location of the hash in
+// PPCallbacks so we don't have to do this workaround.
+class DirectiveCache
+{
+public:
+ DirectiveCache(Preprocessor* PP, FileID FID)
+ : PP(PP)
+ , FID(FID)
+ {
+ SourceManager& SM = this->PP->getSourceManager();
+ const FileEntry* Entry = SM.getFileEntryForID(FID);
+ assert(Entry && "Invalid FileID given");
+
+ Lexer MyLexer(FID, SM.getMemoryBufferForFileOrFake(Entry), SM,
+ this->PP->getLangOpts());
+ Token Tok;
+
+ while (!MyLexer.LexFromRawLexer(Tok)) {
+ if (Tok.getKind() == tok::hash) {
+ assert(SM.getFileID(Tok.getLocation()) == this->FID &&
+ "Token FileID does not match passed FileID");
+ if (!this->HashLocs.empty()) {
+ assert(SM.getFileOffset(this->HashLocs.back()) <
+ SM.getFileOffset(Tok.getLocation()) &&
+ "Tokens in file are not in order");
+ }
+
+ this->HashLocs.push_back(Tok.getLocation());
+ }
+ }
+ }
+
+ SourceRange createRangeForIfndef(SourceLocation IfndefMacroTokLoc)
+ {
+ // The #ifndef of an include guard is likely near the beginning of the
+ // file, so search from the front.
+ return SourceRange(this->findPreviousHashFromFront(IfndefMacroTokLoc),
+ IfndefMacroTokLoc);
+ }
+
+ SourceRange createRangeForDefine(SourceLocation DefineMacroTokLoc)
+ {
+ // The #define of an include guard is likely near the beginning of the
+ // file, so search from the front.
+ return SourceRange(this->findPreviousHashFromFront(DefineMacroTokLoc),
+ DefineMacroTokLoc);
+ }
+
+ SourceRange createRangeForEndif(SourceLocation EndifLoc)
+ {
+ // The #endif of an include guard is likely near the end of the file, so
+ // search from the back.
+ return SourceRange(this->findPreviousHashFromBack(EndifLoc), EndifLoc);
+ }
+
+private:
+ Preprocessor* PP;
+ FileID FID;
+ SmallVector<SourceLocation> HashLocs;
+
+ SourceLocation findPreviousHashFromFront(SourceLocation Loc)
+ {
+ SourceManager& SM = this->PP->getSourceManager();
+ Loc = SM.getExpansionLoc(Loc);
+ assert(SM.getFileID(Loc) == this->FID &&
+ "Loc FileID does not match our FileID");
+
+ auto It = std::find_if(
+ this->HashLocs.begin(), this->HashLocs.end(),
+ [&SM, &Loc](const SourceLocation& OtherLoc) -> bool {
+ return SM.getFileOffset(OtherLoc) >= SM.getFileOffset(Loc);
+ });
+ assert(It != this->HashLocs.begin() &&
+ "No hash associated with passed Loc");
+ return *--It;
+ }
+
+ SourceLocation findPreviousHashFromBack(SourceLocation Loc)
+ {
+ SourceManager& SM = this->PP->getSourceManager();
+ Loc = SM.getExpansionLoc(Loc);
+ assert(SM.getFileID(Loc) == this->FID &&
+ "Loc FileID does not match our FileID");
+
+ auto It =
+ std::find_if(this->HashLocs.rbegin(), this->HashLocs.rend(),
+ [&SM, &Loc](const SourceLocation& OtherLoc) -> bool {
+ return SM.getFileOffset(OtherLoc) < SM.getFileOffset(Loc);
+ });
+ assert(It != this->HashLocs.rend() &&
+ "No hash associated with passed Loc");
+ return *It;
+ }
+};
+
+class UsePragmaOncePPCallbacks : public PPCallbacks
+{
+public:
+ UsePragmaOncePPCallbacks(Preprocessor* PP, UsePragmaOnceCheck* Check)
+ : PP(PP)
+ , Check(Check)
+ {
+ }
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override
+ {
+ // Record all files we enter. We'll need them to diagnose headers without
+ // guards.
+ SourceManager& SM = this->PP->getSourceManager();
+ if (Reason == EnterFile && FileType == SrcMgr::C_User) {
+ if (const FileEntry* FE = SM.getFileEntryForID(SM.getFileID(Loc))) {
+ std::string FileName = cleanPath(FE->getName());
+ this->Files[FileName] = FE;
+ }
+ }
+ }
+
+ void Ifndef(SourceLocation Loc, const Token& MacroNameTok,
+ const MacroDefinition& MD) override
+ {
+ if (MD) {
+ return;
+ }
+
+ // Record #ifndefs that succeeded. We also need the Location of the Name.
+ this->Ifndefs[MacroNameTok.getIdentifierInfo()] =
+ std::make_pair(Loc, MacroNameTok.getLocation());
+ }
+
+ void MacroDefined(const Token& MacroNameTok,
+ const MacroDirective* MD) override
+ {
+ // Record all defined macros. We store the whole token to get info on the
+ // name later.
+ this->Macros.emplace_back(MacroNameTok, MD->getMacroInfo());
+ }
+
+ void Endif(SourceLocation Loc, SourceLocation IfLoc) override
+ {
+ // Record all #endif and the corresponding #ifs (including #ifndefs).
+ this->EndIfs[IfLoc] = Loc;
+ }
+
+ void EndOfMainFile() override
+ {
+ // Now that we have all this information from the preprocessor, use it!
+ SourceManager& SM = this->PP->getSourceManager();
+
+ for (const auto& MacroEntry : this->Macros) {
+ const MacroInfo* MI = MacroEntry.second;
+
+ // We use clang's header guard detection. This has the advantage of also
+ // emitting a warning for cases where a pseudo header guard is found but
+ // preceded by something blocking the header guard optimization.
+ if (!MI->isUsedForHeaderGuard()) {
+ continue;
+ }
+
+ const FileEntry* FE =
+ SM.getFileEntryForID(SM.getFileID(MI->getDefinitionLoc()));
+ std::string FileName = cleanPath(FE->getName());
+ this->Files.erase(FileName);
+
+ // Look up Locations for this guard.
+ SourceLocation Ifndef =
+ this->Ifndefs[MacroEntry.first.getIdentifierInfo()].second;
+ SourceLocation Define = MacroEntry.first.getLocation();
+ SourceLocation EndIf =
+ this
+ ->EndIfs[this->Ifndefs[MacroEntry.first.getIdentifierInfo()].first];
+
+ StringRef CurHeaderGuard =
+ MacroEntry.first.getIdentifierInfo()->getName();
+ std::vector<FixItHint> FixIts;
+
+ HeaderSearch& HeaderInfo = this->PP->getHeaderSearchInfo();
+
+ HeaderFileInfo& Info = HeaderInfo.getFileInfo(FE);
+
+ DirectiveCache Cache(this->PP, SM.getFileID(MI->getDefinitionLoc()));
+ SourceRange IfndefSrcRange = Cache.createRangeForIfndef(Ifndef);
+ SourceRange DefineSrcRange = Cache.createRangeForDefine(Define);
+ SourceRange EndifSrcRange = Cache.createRangeForEndif(EndIf);
+
+ if (Info.isPragmaOnce) {
+ FixIts.push_back(FixItHint::CreateRemoval(IfndefSrcRange));
+ } else {
+ FixIts.push_back(
+ FixItHint::CreateReplacement(IfndefSrcRange, "#pragma once"));
+ }
+
+ FixIts.push_back(FixItHint::CreateRemoval(DefineSrcRange));
+ FixIts.push_back(FixItHint::CreateRemoval(EndifSrcRange));
+
+ this->Check->diag(IfndefSrcRange.getBegin(), "use #pragma once")
+ << FixIts;
+ }
+
+ // Emit warnings for headers that are missing guards.
+ checkGuardlessHeaders();
+ clearAllState();
+ }
+
+ /// Looks for files that were visited but didn't have a header guard.
+ /// Emits a warning with fixits suggesting adding one.
+ void checkGuardlessHeaders()
+ {
+ // Look for header files that didn't have a header guard. Emit a warning
+ // and fix-its to add the guard.
+ // TODO: Insert the guard after top comments.
+ for (const auto& FE : this->Files) {
+ StringRef FileName = FE.getKey();
+ if (!Check->shouldSuggestToAddPragmaOnce(FileName)) {
+ continue;
+ }
+
+ SourceManager& SM = this->PP->getSourceManager();
+ FileID FID = SM.translateFile(FE.getValue());
+ SourceLocation StartLoc = SM.getLocForStartOfFile(FID);
+ if (StartLoc.isInvalid()) {
+ continue;
+ }
+
+ HeaderSearch& HeaderInfo = this->PP->getHeaderSearchInfo();
+
+ HeaderFileInfo& Info = HeaderInfo.getFileInfo(FE.second);
+ if (Info.isPragmaOnce) {
+ continue;
+ }
+
+ this->Check->diag(StartLoc, "use #pragma once")
+ << FixItHint::CreateInsertion(StartLoc, "#pragma once\n");
+ }
+ }
+
+private:
+ void clearAllState()
+ {
+ this->Macros.clear();
+ this->Files.clear();
+ this->Ifndefs.clear();
+ this->EndIfs.clear();
+ }
+
+ std::vector<std::pair<Token, const MacroInfo*>> Macros;
+ llvm::StringMap<const FileEntry*> Files;
+ std::map<const IdentifierInfo*, std::pair<SourceLocation, SourceLocation>>
+ Ifndefs;
+ std::map<SourceLocation, SourceLocation> EndIfs;
+
+ Preprocessor* PP;
+ UsePragmaOnceCheck* Check;
+};
+} // namespace
+
+void UsePragmaOnceCheck::storeOptions(ClangTidyOptions::OptionMap& Opts)
+{
+ this->Options.store(Opts, "HeaderFileExtensions",
+ RawStringHeaderFileExtensions);
+}
+
+void UsePragmaOnceCheck::registerPPCallbacks(const SourceManager& SM,
+ Preprocessor* PP,
+ Preprocessor* ModuleExpanderPP)
+{
+ PP->addPPCallbacks(std::make_unique<UsePragmaOncePPCallbacks>(PP, this));
+}
+
+bool UsePragmaOnceCheck::shouldSuggestToAddPragmaOnce(StringRef FileName)
+{
+ return utils::isFileExtension(FileName, this->HeaderFileExtensions);
+}
+
+} // namespace cmake
+} // namespace tidy
+} // namespace clang
diff --git a/Utilities/ClangTidyModule/UsePragmaOnceCheck.h b/Utilities/ClangTidyModule/UsePragmaOnceCheck.h
new file mode 100644
index 0000000..08c2099
--- /dev/null
+++ b/Utilities/ClangTidyModule/UsePragmaOnceCheck.h
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+/* This code was originally taken from part of the Clang-Tidy LLVM project and
+ * modified for use with CMake under the following original license: */
+
+//===--- HeaderGuard.h - clang-tidy -----------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions. See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include <clang-tidy/ClangTidyCheck.h>
+#include <clang-tidy/utils/FileExtensionsUtils.h>
+
+namespace clang {
+namespace tidy {
+namespace cmake {
+
+/// Finds and replaces header guards with pragma once.
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a semicolon-separated list of filename
+/// extensions of header files (The filename extension should not contain
+/// "." prefix). ";h;hh;hpp;hxx" by default.
+///
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between ";" if there are other filename extensions.
+class UsePragmaOnceCheck : public ClangTidyCheck
+{
+public:
+ UsePragmaOnceCheck(StringRef Name, ClangTidyContext* Context)
+ : ClangTidyCheck(Name, Context)
+ , RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions()))
+ {
+ utils::parseFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions,
+ utils::defaultFileExtensionDelimiters());
+ }
+ void storeOptions(ClangTidyOptions::OptionMap& Opts) override;
+ void registerPPCallbacks(const SourceManager& SM, Preprocessor* PP,
+ Preprocessor* ModuleExpanderPP) override;
+
+ /// Returns ``true`` if the check should add pragma once to the file
+ /// if it has none.
+ virtual bool shouldSuggestToAddPragmaOnce(StringRef Filename);
+
+private:
+ std::string RawStringHeaderFileExtensions;
+ utils::FileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace cmake
+} // namespace tidy
+} // namespace clang
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index bc16350..b084dd5 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeDeveloperReference_STANDALONE 1)
- cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index b0ed911..1afad43 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -76,9 +76,10 @@
# __decay_and_strip is used internally in the C++11 standard library.
# IWYU does not classify it as internal and suggests to add <type_traits>.
# To ignore it, we simply map it to a file that is included anyway.
- # Use '-Xiwyu -v7' to see the fully qualified names that need this.
+ # Use 'CMake_IWYU_VERBOSE' to see the fully qualified names that need this.
# TODO: Can this be simplified with an @-expression?
#{ symbol: [ "@std::__decay_and_strip<.*>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<int>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<bool>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<char const (&)[1]>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmCommand *&>::__type", private, "\"cmConfigure.h\"", public ] },
@@ -101,6 +102,7 @@
# Wrappers for 3rd-party libraries
{ include: [ "@<.*curl/curlver.h>", private, "<cm3p/curl/curl.h>", public ] },
+ { include: [ "@<.*curl/system.h>", private, "<cm3p/curl/curl.h>", public ] },
{ include: [ "@<.*json/config.h>", private, "<cm3p/json/value.h>", public ] },
{ include: [ "@<.*json/forwards.h>", private, "<cm3p/json/value.h>", public ] },
{ include: [ "@<.*uv/.+\\.h>", private, "<cm3p/uv.h>", public ] },
diff --git a/Utilities/Scripts/clang-format.bash b/Utilities/Scripts/clang-format.bash
index 7ca4433..27ed40f 100755
--- a/Utilities/Scripts/clang-format.bash
+++ b/Utilities/Scripts/clang-format.bash
@@ -40,7 +40,7 @@ Example to format files modified by the most recent commit:
Utilities/Scripts/clang-format.bash --amend
-Example to format all files:
+Example to format all files tracked by Git:
Utilities/Scripts/clang-format.bash --tracked
@@ -78,7 +78,7 @@ test "$#" = 0 || die "$usage"
# Find a default tool.
tools='
- clang-format-6.0
+ clang-format-15
clang-format
'
if test "x$clang_format" = "x"; then
@@ -96,8 +96,8 @@ if ! type -p "$clang_format" >/dev/null; then
exit 1
fi
-if ! "$clang_format" --version | grep 'clang-format version 6\.0' >/dev/null 2>/dev/null; then
- echo "clang-format version 6.0 is required (exactly)"
+if ! "$clang_format" --version | grep 'clang-format version 15' >/dev/null 2>/dev/null; then
+ echo "clang-format version 15 is required (exactly)"
exit 1
fi
@@ -115,10 +115,8 @@ esac
$git_ls |
# Select sources with our attribute.
- git check-attr --stdin format.clang-format-6.0 |
- grep -e ': format\.clang-format-6\.0: set$' |
- sed -n 's/:[^:]*:[^:]*$//p' |
+ git check-attr --stdin format.clang-format |
+ sed -n '/: format\.clang-format: \(set\|15\)$/ {s/:[^:]*:[^:]*$//p}' |
# Update sources in-place.
- tr '\n' '\0' |
- xargs -0 "$clang_format" -i
+ xargs -d '\n' "$clang_format" -i
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index 5b66d15..856ae81 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -8,7 +8,7 @@ readonly name="curl"
readonly ownership="Curl Upstream <curl-library@lists.haxx.se>"
readonly subtree="Utilities/cmcurl"
readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_86_0"
+readonly tag="curl-7_87_0"
readonly shortlog=false
readonly paths="
CMake/*
diff --git a/Utilities/Scripts/update-nghttp2.bash b/Utilities/Scripts/update-nghttp2.bash
index 07a8f13..c638efe 100755
--- a/Utilities/Scripts/update-nghttp2.bash
+++ b/Utilities/Scripts/update-nghttp2.bash
@@ -8,7 +8,7 @@ readonly name="nghttp2"
readonly ownership="nghttp2 upstream <kwrobot@kitware.com>"
readonly subtree="Utilities/cmnghttp2"
readonly repo="https://github.com/nghttp2/nghttp2.git"
-readonly tag="v1.40.0"
+readonly tag="v1.52.0" # When updating, sync PACKAGE_VERSION below!
readonly shortlog=false
readonly paths="
COPYING
@@ -23,7 +23,7 @@ extract_source () {
pushd "${extractdir}/${name}-reduced"
echo "* -whitespace" > .gitattributes
mv lib/includes/nghttp2/nghttp2ver.h.in lib/includes/nghttp2/nghttp2ver.h
- sed -i 's/@PACKAGE_VERSION@/1.40.0/;s/@PACKAGE_VERSION_NUM@/0x012800/' lib/includes/nghttp2/nghttp2ver.h
+ sed -i 's/@PACKAGE_VERSION@/1.52.0/;s/@PACKAGE_VERSION_NUM@/0x013400/' lib/includes/nghttp2/nghttp2ver.h
popd
}
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index 886f4e0..a9aa47d 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeHelp_STANDALONE 1)
- cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
@@ -22,6 +22,7 @@ option(SPHINX_INFO "Build Info manual with Sphinx" OFF)
option(SPHINX_MAN "Build man pages with Sphinx" OFF)
option(SPHINX_HTML "Build html help with Sphinx" OFF)
option(SPHINX_SINGLEHTML "Build html single page help with Sphinx" OFF)
+option(SPHINX_LINKCHECK "Check external links mentioned in documentation" OFF)
option(SPHINX_QTHELP "Build Qt help with Sphinx" OFF)
option(SPHINX_LATEXPDF "Build PDF help with Sphinx using LaTeX" OFF)
option(SPHINX_TEXT "Build text help with Sphinx (not installed)" OFF)
@@ -35,7 +36,15 @@ separate_arguments(sphinx_flags UNIX_COMMAND "${SPHINX_FLAGS}")
mark_as_advanced(SPHINX_TEXT)
mark_as_advanced(SPHINX_FLAGS)
-if(NOT SPHINX_INFO AND NOT SPHINX_MAN AND NOT SPHINX_HTML AND NOT SPHINX_SINGLEHTML AND NOT SPHINX_QTHELP AND NOT SPHINX_TEXT AND NOT SPHINX_LATEXPDF)
+if(NOT (SPHINX_INFO
+ OR SPHINX_MAN
+ OR SPHINX_HTML
+ OR SPHINX_SINGLEHTML
+ OR SPHINX_LINKCHECK
+ OR SPHINX_QTHELP
+ OR SPHINX_TEXT
+ OR SPHINX_LATEXPDF
+ ))
return()
elseif(NOT SPHINX_EXECUTABLE)
message(FATAL_ERROR "SPHINX_EXECUTABLE (sphinx-build) is not found!")
@@ -79,6 +88,13 @@ endif()
if(SPHINX_SINGLEHTML)
list(APPEND doc_formats singlehtml)
endif()
+if(SPHINX_LINKCHECK)
+ list(APPEND doc_formats linkcheck)
+ #
+ set(linkcheck_post_commands
+ COMMAND ${CMAKE_COMMAND} -E echo "sphinx-build linkcheck: see checking status in file://${CMAKE_CURRENT_BINARY_DIR}/linkcheck/output.txt"
+ )
+endif()
if(SPHINX_TEXT)
list(APPEND doc_formats text)
endif()
@@ -159,11 +175,41 @@ if(CMake_SPHINX_CMAKE_ORG)
)
endif()
+# Redirect `sphinx-build` output to `build-<format>.log` file?
+set(sphinx_use_build_log TRUE)
+set(sphinx_verbose_levels "DEBUG;TRACE")
+set(sphinx_no_redirect_levels "VERBOSE;${sphinx_verbose_levels}")
+# NOTE There is no generic verbosity level for all supported generators,
+# so lets use CMake verbosity level to control if `sphinx-build` should
+# redirect it's output to a file or a user wants to see it at build time.
+if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25)
+ cmake_language(GET_MESSAGE_LOG_LEVEL verbose_level)
+else()
+ # If building under CMake < 3.25, fallback to `CMAKE_MESSAGE_LOG_LEVEL`
+ # variable. It was added in 3.17 but it's OK to set it even for older
+ # versions (w/o any effect on `message()` command of course).
+ set(verbose_level ${CMAKE_MESSAGE_LOG_LEVEL})
+endif()
+if(DEFINED ENV{VERBOSE} OR CMAKE_VERBOSE_MAKEFILE OR verbose_level IN_LIST sphinx_no_redirect_levels)
+ set(sphinx_use_build_log FALSE)
+ if(verbose_level IN_LIST sphinx_verbose_levels)
+ # NOTE Sphinx accept multiple `-v` options for more verbosity
+ # but the output mostly for Sphinx developers...
+ list(APPEND sphinx_flags "-v")
+ endif()
+endif()
+
set(doc_format_outputs "")
set(doc_format_last "")
foreach(format IN LISTS doc_formats)
set(doc_format_output "doc_format_${format}")
- set(doc_format_log "build-${format}.log")
+ set(doc_format_log "")
+ set(build_comment_tail " ...")
+ if(sphinx_use_build_log)
+ set(doc_format_log "build-${format}.log")
+ set(build_comment_tail ": see Utilities/Sphinx/${doc_format_log}")
+ list(PREPEND doc_format_log ">")
+ endif()
if(CMake_SPHINX_CMAKE_ORG)
set(doctrees "doctrees/${format}")
else()
@@ -172,43 +218,37 @@ foreach(format IN LISTS doc_formats)
if(format STREQUAL "latexpdf")
# This format does not use builder (-b) but make_mode (-M) which expects
# arguments in peculiar order
- add_custom_command(
- OUTPUT ${doc_format_output}
- ${${format}_pre_commands}
- COMMAND ${SPHINX_EXECUTABLE}
- -M ${format}
- ${CMake_SOURCE_DIR}/Help
- ${CMAKE_CURRENT_BINARY_DIR}/${format}
- -c ${CMAKE_CURRENT_BINARY_DIR}
- -d ${CMAKE_CURRENT_BINARY_DIR}/${doctrees}
- ${sphinx_flags}
- ${doc_${format}_opts}
- > ${doc_format_log} # log stdout, pass stderr
- ${${format}_post_commands}
- DEPENDS ${doc_format_last}
- COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
- VERBATIM
+ set(_args
+ -M ${format}
+ ${CMake_SOURCE_DIR}/Help
+ ${CMAKE_CURRENT_BINARY_DIR}/${format}
+ -c ${CMAKE_CURRENT_BINARY_DIR}
+ -d ${CMAKE_CURRENT_BINARY_DIR}/${doctrees}
+ ${sphinx_flags}
+ ${doc_${format}_opts}
)
else()
# other formats use standard builder (-b) mode
- add_custom_command(
- OUTPUT ${doc_format_output}
- ${${format}_pre_commands}
- COMMAND ${SPHINX_EXECUTABLE}
- -c ${CMAKE_CURRENT_BINARY_DIR}
- -d ${CMAKE_CURRENT_BINARY_DIR}/${doctrees}
- -b ${format}
- ${sphinx_flags}
- ${doc_${format}_opts}
- ${CMake_SOURCE_DIR}/Help
- ${CMAKE_CURRENT_BINARY_DIR}/${format}
- > ${doc_format_log} # log stdout, pass stderr
- ${${format}_post_commands}
- DEPENDS ${doc_format_last}
- COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
- VERBATIM
+ set(_args
+ -c ${CMAKE_CURRENT_BINARY_DIR}
+ -d ${CMAKE_CURRENT_BINARY_DIR}/${doctrees}
+ -b ${format}
+ ${sphinx_flags}
+ ${doc_${format}_opts}
+ ${CMake_SOURCE_DIR}/Help
+ ${CMAKE_CURRENT_BINARY_DIR}/${format}
)
endif()
+
+ add_custom_command(
+ OUTPUT ${doc_format_output}
+ ${${format}_pre_commands}
+ COMMAND ${SPHINX_EXECUTABLE} ${_args} ${doc_format_log}
+ ${${format}_post_commands}
+ DEPENDS ${doc_format_last}
+ COMMENT "sphinx-build ${format}${build_comment_tail}"
+ VERBATIM
+ )
set_property(SOURCE ${doc_format_output} PROPERTY SYMBOLIC 1)
list(APPEND doc_format_outputs ${doc_format_output})
if(NOT CMake_SPHINX_CMAKE_ORG)
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index c7b1233..47e4909 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -475,3 +475,4 @@ def setup(app):
app.add_transform(CMakeTransform)
app.add_transform(CMakeXRefTransform)
app.add_domain(CMakeDomain)
+ return {"parallel_read_safe": True}
diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in
index 2b3083b..fc3ecb5 100644
--- a/Utilities/Sphinx/conf.py.in
+++ b/Utilities/Sphinx/conf.py.in
@@ -87,3 +87,5 @@ html_favicon = '@conf_path@/static/cmake-favicon.ico'
# https://bitbucket.org/birkenfeld/sphinx/issue/1448/make-qthelp-more-configurable
# qthelp_namespace = "org.cmake"
# qthelp_qch_name = "CMake.qch"
+
+linkcheck_ignore = [r'about:|https://gitlab.kitware.com/cmake/community/-/wikis/doc/cpack']
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index b3031f7..ed8d28a 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -85,51 +85,51 @@ endif()
unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
-if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+if(NOT CMAKE_CROSSCOMPILING)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
- # only try this on non-apple platforms
-
- # if not cross-compilation...
- include(CheckCSourceRuns)
- set(CMAKE_REQUIRED_FLAGS "")
- if(HAVE_SYS_POLL_H)
- set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
- elseif(HAVE_POLL_H)
- set(CMAKE_REQUIRED_FLAGS "-DHAVE_POLL_H")
- endif()
- check_c_source_runs("
- #include <stdlib.h>
- #include <sys/time.h>
-
- #ifdef HAVE_SYS_POLL_H
- # include <sys/poll.h>
- #elif HAVE_POLL_H
- # include <poll.h>
- #endif
-
- int main(void)
- {
- if(0 != poll(0, 0, 10)) {
- return 1; /* fail */
- }
- else {
- /* detect the 10.12 poll() breakage */
- struct timeval before, after;
- int rc;
- size_t us;
-
- gettimeofday(&before, NULL);
- rc = poll(NULL, 0, 500);
- gettimeofday(&after, NULL);
-
- us = (after.tv_sec - before.tv_sec) * 1000000 +
- (after.tv_usec - before.tv_usec);
-
- if(us < 400000) {
- return 1;
+ # only try this on non-apple platforms
+
+ # if not cross-compilation...
+ include(CheckCSourceRuns)
+ set(CMAKE_REQUIRED_FLAGS "")
+ if(HAVE_SYS_POLL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
+ elseif(HAVE_POLL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_POLL_H")
+ endif()
+ check_c_source_runs("
+ #include <stdlib.h>
+ #include <sys/time.h>
+
+ #ifdef HAVE_SYS_POLL_H
+ # include <sys/poll.h>
+ #elif HAVE_POLL_H
+ # include <poll.h>
+ #endif
+
+ int main(void)
+ {
+ if(0 != poll(0, 0, 10)) {
+ return 1; /* fail */
+ }
+ else {
+ /* detect the 10.12 poll() breakage */
+ struct timeval before, after;
+ int rc;
+ size_t us;
+
+ gettimeofday(&before, NULL);
+ rc = poll(NULL, 0, 500);
+ gettimeofday(&after, NULL);
+
+ us = (after.tv_sec - before.tv_sec) * 1000000 +
+ (after.tv_usec - before.tv_usec);
+
+ if(us < 400000) {
+ return 1;
+ }
}
- }
- return 0;
+ return 0;
}" HAVE_POLL_FINE)
endif()
endif()
diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
index 9a513bb..3cb4ffe 100644
--- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
+++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
@@ -34,7 +34,6 @@ if(NOT UNIX)
set(HAVE_NETDB_H 0)
set(HAVE_NETINET_IN_H 0)
set(HAVE_NET_IF_H 0)
- set(HAVE_PROCESS_H 1)
set(HAVE_PWD_H 0)
set(HAVE_SETJMP_H 1)
set(HAVE_SIGNAL_H 1)
@@ -71,7 +70,6 @@ if(NOT UNIX)
set(HAVE_UTIME 1)
set(HAVE_RAND_EGD 0)
set(HAVE_GMTIME_R 0)
- set(HAVE_GETADDRINFO_THREADSAFE 1)
set(HAVE_GETHOSTBYNAME_R 0)
set(HAVE_SIGNAL 1)
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index de5df3e..49016c8 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -275,7 +275,7 @@ endif()
option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
-if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(PICKY_COMPILER)
foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wfloat-equal -Wsign-compare -Wundef -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wvla -Wdouble-promotion -Wenum-conversion -Warith-conversion)
# surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
@@ -867,7 +867,6 @@ if(WIN32)
option(USE_WIN32_IDN "Use WinIDN for IDN support" OFF)
if(USE_WIN32_IDN)
list(APPEND CURL_LIBS "normaliz")
- set(WANT_IDN_PROTOTYPES ON)
endif()
endif()
@@ -1016,6 +1015,7 @@ if(CURL_USE_GSSAPI)
include_directories(${GSS_INCLUDE_DIR})
link_directories(${GSS_LINK_DIRECTORIES})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
+ string(REPLACE ";" " " GSS_LINKER_FLAGS "${GSS_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
@@ -1146,8 +1146,6 @@ check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H)
check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H)
check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H)
check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H)
-check_include_file_concat("assert.h" HAVE_ASSERT_H)
-check_include_file_concat("errno.h" HAVE_ERRNO_H)
check_include_file_concat("fcntl.h" HAVE_FCNTL_H)
check_include_file_concat("idn2.h" HAVE_IDN2_H)
check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H)
@@ -1178,7 +1176,6 @@ check_include_file_concat("time.h" HAVE_TIME_H)
check_include_file_concat("unistd.h" HAVE_UNISTD_H)
check_include_file_concat("utime.h" HAVE_UTIME_H)
-check_include_file_concat("process.h" HAVE_PROCESS_H)
check_include_file_concat("stddef.h" HAVE_STDDEF_H)
check_include_file_concat("stdint.h" HAVE_STDINT_H)
check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H)
@@ -1235,8 +1232,8 @@ check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64)
check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R)
check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO)
-if(NOT HAVE_GETADDRINFO)
- set(HAVE_GETADDRINFO_THREADSAFE OFF)
+if(WIN32)
+ set(HAVE_GETADDRINFO_THREADSAFE ${HAVE_GETADDRINFO})
endif()
check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE)
@@ -1638,7 +1635,10 @@ _add_if("TLS-SRP" USE_TLS_SRP)
_add_if("HTTP2" USE_NGHTTP2)
_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE)
_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
-_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS))
+# TODO wolfSSL only support this from v5.0.0 onwards
+_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS
+ OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
+ USE_MBEDTLS OR USE_SECTRANSP))
_add_if("unicode" ENABLE_UNICODE)
_add_if("threadsafe" HAVE_ATOMIC OR (WIN32 AND
HAVE_WIN32_WINNT GREATER_EQUAL 0x600))
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index 7a12581..b354757 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -33,6 +33,22 @@
#define CURL_STRICTER
#endif
+/* Compile-time deprecation macros. */
+#if defined(__GNUC__) && (__GNUC__ >= 6) && \
+ !defined(__INTEL_COMPILER) && \
+ !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
+#define CURL_DEPRECATED(version, message) \
+ __attribute__((deprecated("since " # version ". " message)))
+#define CURL_IGNORE_DEPRECATION(statements) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+ statements \
+ _Pragma("GCC diagnostic pop")
+#else
+#define CURL_DEPRECATED(version, message)
+#define CURL_IGNORE_DEPRECATION(statements) statements
+#endif
+
#include "curlver.h" /* libcurl version defines */
#include "system.h" /* determine things run-time */
@@ -76,7 +92,7 @@
defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
(defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
- defined(__sun__)
+ defined(__sun__) || defined(__serenity__)
#include <sys/select.h>
#endif
@@ -145,11 +161,11 @@ typedef enum {
CURLSSLBACKEND_NSS = 3,
CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */
CURLSSLBACKEND_GSKIT = 5,
- CURLSSLBACKEND_POLARSSL = 6,
+ CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6,
CURLSSLBACKEND_WOLFSSL = 7,
CURLSSLBACKEND_SCHANNEL = 8,
CURLSSLBACKEND_SECURETRANSPORT = 9,
- CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
+ CURLSSLBACKEND_AXTLS CURL_DEPRECATED(7.61.0, "") = 10,
CURLSSLBACKEND_MBEDTLS = 11,
CURLSSLBACKEND_MESALINK = 12,
CURLSSLBACKEND_BEARSSL = 13,
@@ -256,6 +272,10 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
will signal libcurl to pause receiving on the current transfer. */
#define CURL_WRITEFUNC_PAUSE 0x10000001
+/* This is a magic return code for the write callback that, when returned,
+ will signal an error from the callback. */
+#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
+
typedef size_t (*curl_write_callback)(char *buffer,
size_t size,
size_t nitems,
@@ -368,7 +388,7 @@ typedef int (*curl_seek_callback)(void *instream,
#define CURL_READFUNC_PAUSE 0x10000001
/* Return code for when the trailing headers' callback has terminated
- without any errors*/
+ without any errors */
#define CURL_TRAILERFUNC_OK 0
/* Return code for when was an error in the trailing header's list and we
want to abort the request */
@@ -450,7 +470,7 @@ typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
#define CURL_DID_MEMORY_FUNC_TYPEDEFS
#endif
-/* the kind of data that is passed to information_callback*/
+/* the kind of data that is passed to information_callback */
typedef enum {
CURLINFO_TEXT = 0,
CURLINFO_HEADER_IN, /* 1 */
@@ -698,7 +718,7 @@ typedef enum {
#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
-#endif /*!CURL_NO_OLDIES*/
+#endif /* !CURL_NO_OLDIES */
/*
* Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was
@@ -843,7 +863,7 @@ enum curl_khstat {
CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now.
Causes a CURLE_PEER_FAILED_VERIFICATION error but the
connection will be left intact etc */
- CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key*/
+ CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */
};
@@ -864,13 +884,13 @@ typedef int
/* CURLOPT_SSH_KEYDATA */
typedef int
- (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed*/
+ (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */
/* with CURLOPT_SSH_HOSTKEYDATA */
int keytype, /* CURLKHTYPE */
- const char *key, /*hostkey to check*/
- size_t keylen); /*length of the key*/
- /*return CURLE_OK to accept*/
- /*or something else to refuse*/
+ const char *key, /* hostkey to check */
+ size_t keylen); /* length of the key */
+ /* return CURLE_OK to accept */
+ /* or something else to refuse */
/* parameter for the CURLOPT_USE_SSL option */
@@ -932,7 +952,7 @@ typedef enum {
#define CURLFTPSSL_ALL CURLUSESSL_ALL
#define CURLFTPSSL_LAST CURLUSESSL_LAST
#define curl_ftpssl curl_usessl
-#endif /*!CURL_NO_OLDIES*/
+#endif /* !CURL_NO_OLDIES */
/* parameter for the CURLOPT_FTP_SSL_CCC option */
typedef enum {
@@ -1058,6 +1078,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
#define CURLOPT(na,t,nu) na = t + nu
+#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu
/* CURLOPT aliases that make no run-time difference */
@@ -1119,7 +1140,7 @@ typedef enum {
/* Time-out the read operation after this amount of seconds */
CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13),
- /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+ /* If CURLOPT_READDATA is used, this can be used to inform libcurl about
* how large the file being sent really is. That allows better error
* checking and better verifies that the upload was successful. -1 means
* unknown size.
@@ -1171,7 +1192,8 @@ typedef enum {
CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23),
/* This points to a linked list of post entries, struct curl_httppost */
- CURLOPT(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24),
+ CURLOPTDEPRECATED(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24,
+ 7.56.0, "Use CURLOPT_MIMEPOST"),
/* name of the file keeping your private SSL-certificate */
CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25),
@@ -1261,7 +1283,8 @@ typedef enum {
CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53),
/* HTTP PUT */
- CURLOPT(CURLOPT_PUT, CURLOPTTYPE_LONG, 54),
+ CURLOPTDEPRECATED(CURLOPT_PUT, CURLOPTTYPE_LONG, 54,
+ 7.12.1, "Use CURLOPT_UPLOAD"),
/* 55 = OBSOLETE */
@@ -1269,7 +1292,8 @@ typedef enum {
* Function that will be called instead of the internal progress display
* function. This function should be defined as the curl_progress_callback
* prototype defines. */
- CURLOPT(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56),
+ CURLOPTDEPRECATED(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56,
+ 7.32.0, "Use CURLOPT_XFERINFOFUNCTION"),
/* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
callbacks */
@@ -1286,7 +1310,7 @@ typedef enum {
/* size of the POST input data, if strlen() is not good to use */
CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60),
- /* tunnel non-http operations through a HTTP proxy */
+ /* tunnel non-http operations through an HTTP proxy */
CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),
/* Set the interface string to use as outgoing network interface */
@@ -1337,10 +1361,12 @@ typedef enum {
/* Set to a file name that contains random data for libcurl to use to
seed the random engine when doing SSL connects. */
- CURLOPT(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76),
+ CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
+ 7.84.0, "Serves no purpose anymore"),
/* Set to the Entropy Gathering Daemon socket pathname */
- CURLOPT(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77),
+ CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77,
+ 7.84.0, "Serves no purpose anymore"),
/* Time-out connect operations after this amount of seconds, if connects are
OK within this time, then fine... This only aborts the connect phase. */
@@ -1395,7 +1421,8 @@ typedef enum {
/* Non-zero value means to use the global dns cache */
/* DEPRECATED, do not use! */
- CURLOPT(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91),
+ CURLOPTDEPRECATED(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91,
+ 7.11.1, "Use CURLOPT_SHARE"),
/* DNS cache timeout */
CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92),
@@ -1550,8 +1577,10 @@ typedef enum {
*/
CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129),
- CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130),
- CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131),
+ CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130,
+ 7.18.0, "Use CURLOPT_SEEKFUNCTION"),
+ CURLOPTDEPRECATED(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131,
+ 7.18.0, "Use CURLOPT_SEEKDATA"),
/* 132 OBSOLETE. Gone in 7.16.0 */
/* 133 OBSOLETE. Gone in 7.16.0 */
@@ -1590,16 +1619,22 @@ typedef enum {
/* Function that will be called to convert from the
network encoding (instead of using the iconv calls in libcurl) */
- CURLOPT(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142),
+ CURLOPTDEPRECATED(CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+ CURLOPTTYPE_FUNCTIONPOINT, 142,
+ 7.82.0, "Serves no purpose anymore"),
/* Function that will be called to convert to the
network encoding (instead of using the iconv calls in libcurl) */
- CURLOPT(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143),
+ CURLOPTDEPRECATED(CURLOPT_CONV_TO_NETWORK_FUNCTION,
+ CURLOPTTYPE_FUNCTIONPOINT, 143,
+ 7.82.0, "Serves no purpose anymore"),
/* Function that will be called to convert from UTF8
(instead of using the iconv calls in libcurl)
Note that this is used only for SSL certificate processing */
- CURLOPT(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144),
+ CURLOPTDEPRECATED(CURLOPT_CONV_FROM_UTF8_FUNCTION,
+ CURLOPTTYPE_FUNCTIONPOINT, 144,
+ 7.82.0, "Serves no purpose anymore"),
/* if the connection proceeds too quickly then need to slow it down */
/* limit-rate: maximum number of bytes per second to send or receive */
@@ -1700,7 +1735,9 @@ typedef enum {
/* Socks Service */
/* DEPRECATED, do not use! */
- CURLOPT(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179),
+ CURLOPTDEPRECATED(CURLOPT_SOCKS5_GSSAPI_SERVICE,
+ CURLOPTTYPE_STRINGPOINT, 179,
+ 7.49.0, "Use CURLOPT_PROXY_SERVICE_NAME"),
/* Socks Service */
CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180),
@@ -1709,12 +1746,14 @@ typedef enum {
transfer, which thus helps the app which takes URLs from users or other
external inputs and want to restrict what protocol(s) to deal
with. Defaults to CURLPROTO_ALL. */
- CURLOPT(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181),
+ CURLOPTDEPRECATED(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181,
+ 7.85.0, "Use CURLOPT_PROTOCOLS_STR"),
/* set the bitmask for the protocols that libcurl is allowed to follow to,
as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
to be set in both bitmasks to be allowed to get redirected to. */
- CURLOPT(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182),
+ CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
+ 7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),
/* set the SSH knownhost file name to use */
CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
@@ -1859,12 +1898,13 @@ typedef enum {
CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224),
/* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
- CURLOPT(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225),
+ CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225,
+ 7.86.0, "Has no function"),
/* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226),
- /* Time to wait for a response to a HTTP request containing an
+ /* Time to wait for a response to an HTTP request containing an
* Expect: 100-continue header before sending the data anyway. */
CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227),
@@ -2157,6 +2197,12 @@ typedef enum {
/* websockets options */
CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320),
+ /* CA cache timeout */
+ CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321),
+
+ /* Can leak things, gonna exit() soon */
+ CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2444,30 +2490,32 @@ CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part,
int take_ownership);
typedef enum {
- CURLFORM_NOTHING, /********* the first one is unused ************/
- CURLFORM_COPYNAME,
- CURLFORM_PTRNAME,
- CURLFORM_NAMELENGTH,
- CURLFORM_COPYCONTENTS,
- CURLFORM_PTRCONTENTS,
- CURLFORM_CONTENTSLENGTH,
- CURLFORM_FILECONTENT,
- CURLFORM_ARRAY,
+ /********* the first one is unused ************/
+ CURLFORM_NOTHING CURL_DEPRECATED(7.56.0, ""),
+ CURLFORM_COPYNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+ CURLFORM_PTRNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+ CURLFORM_NAMELENGTH CURL_DEPRECATED(7.56.0, ""),
+ CURLFORM_COPYCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+ CURLFORM_PTRCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+ CURLFORM_CONTENTSLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+ CURLFORM_FILECONTENT CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+ CURLFORM_ARRAY CURL_DEPRECATED(7.56.0, ""),
CURLFORM_OBSOLETE,
- CURLFORM_FILE,
+ CURLFORM_FILE CURL_DEPRECATED(7.56.0, "Use curl_mime_filedata()"),
- CURLFORM_BUFFER,
- CURLFORM_BUFFERPTR,
- CURLFORM_BUFFERLENGTH,
+ CURLFORM_BUFFER CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
+ CURLFORM_BUFFERPTR CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+ CURLFORM_BUFFERLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
- CURLFORM_CONTENTTYPE,
- CURLFORM_CONTENTHEADER,
- CURLFORM_FILENAME,
+ CURLFORM_CONTENTTYPE CURL_DEPRECATED(7.56.0, "Use curl_mime_type()"),
+ CURLFORM_CONTENTHEADER CURL_DEPRECATED(7.56.0, "Use curl_mime_headers()"),
+ CURLFORM_FILENAME CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
CURLFORM_END,
CURLFORM_OBSOLETE2,
- CURLFORM_STREAM,
- CURLFORM_CONTENTLEN, /* added in 7.46.0, provide a curl_off_t length */
+ CURLFORM_STREAM CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+ CURLFORM_CONTENTLEN /* added in 7.46.0, provide a curl_off_t length */
+ CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
CURLFORM_LASTENTRY /* the last unused */
} CURLformoption;
@@ -2495,15 +2543,16 @@ struct curl_forms {
*
***************************************************************************/
typedef enum {
- CURL_FORMADD_OK, /* first, no error */
+ CURL_FORMADD_OK CURL_DEPRECATED(7.56.0, ""), /* 1st, no error */
- CURL_FORMADD_MEMORY,
- CURL_FORMADD_OPTION_TWICE,
- CURL_FORMADD_NULL,
- CURL_FORMADD_UNKNOWN_OPTION,
- CURL_FORMADD_INCOMPLETE,
- CURL_FORMADD_ILLEGAL_ARRAY,
- CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+ CURL_FORMADD_MEMORY CURL_DEPRECATED(7.56.0, ""),
+ CURL_FORMADD_OPTION_TWICE CURL_DEPRECATED(7.56.0, ""),
+ CURL_FORMADD_NULL CURL_DEPRECATED(7.56.0, ""),
+ CURL_FORMADD_UNKNOWN_OPTION CURL_DEPRECATED(7.56.0, ""),
+ CURL_FORMADD_INCOMPLETE CURL_DEPRECATED(7.56.0, ""),
+ CURL_FORMADD_ILLEGAL_ARRAY CURL_DEPRECATED(7.56.0, ""),
+ /* libcurl was built with form api disabled */
+ CURL_FORMADD_DISABLED CURL_DEPRECATED(7.56.0, ""),
CURL_FORMADD_LAST /* last */
} CURLFORMcode;
@@ -2517,9 +2566,10 @@ typedef enum {
* adds one part that together construct a full post. Then use
* CURLOPT_HTTPPOST to send it off to libcurl.
*/
-CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...);
+CURL_EXTERN CURLFORMcode CURL_DEPRECATED(7.56.0, "Use curl_mime_init()")
+curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...);
/*
* callback function for curl_formget()
@@ -2542,8 +2592,9 @@ typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
* the curl_formget_callback function.
* Returns 0 on success.
*/
-CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
- curl_formget_callback append);
+CURL_EXTERN int CURL_DEPRECATED(7.56.0, "")
+curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append);
/*
* NAME curl_formfree()
*
@@ -2551,7 +2602,8 @@ CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
*
* Free a multipart formpost previously built with curl_formadd().
*/
-CURL_EXTERN void curl_formfree(struct curl_httppost *form);
+CURL_EXTERN void CURL_DEPRECATED(7.56.0, "Use curl_mime_free()")
+curl_formfree(struct curl_httppost *form);
/*
* NAME curl_getenv()
@@ -2720,8 +2772,8 @@ CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
* Appends a string to a linked list. If no list exists, it will be created
* first. Returns the new list, after appending.
*/
-CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
- const char *);
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *list,
+ const char *data);
/*
* NAME curl_slist_free_all()
@@ -2730,7 +2782,7 @@ CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
*
* free a previously built curl_slist.
*/
-CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *list);
/*
* NAME curl_getdate()
@@ -2778,22 +2830,35 @@ typedef enum {
CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
- CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7,
+ CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T")
+ = CURLINFO_DOUBLE + 7,
CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7,
- CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8,
+ CURLINFO_SIZE_DOWNLOAD
+ CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_DOWNLOAD_T")
+ = CURLINFO_DOUBLE + 8,
CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8,
- CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9,
+ CURLINFO_SPEED_DOWNLOAD
+ CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_DOWNLOAD_T")
+ = CURLINFO_DOUBLE + 9,
CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9,
- CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10,
+ CURLINFO_SPEED_UPLOAD
+ CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_UPLOAD_T")
+ = CURLINFO_DOUBLE + 10,
CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10,
CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11,
CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
CURLINFO_FILETIME = CURLINFO_LONG + 14,
CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14,
- CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
+ CURLINFO_CONTENT_LENGTH_DOWNLOAD
+ CURL_DEPRECATED(7.55.0,
+ "Use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T")
+ = CURLINFO_DOUBLE + 15,
CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15,
- CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
+ CURLINFO_CONTENT_LENGTH_UPLOAD
+ CURL_DEPRECATED(7.55.0,
+ "Use CURLINFO_CONTENT_LENGTH_UPLOAD_T")
+ = CURLINFO_DOUBLE + 16,
CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16,
CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
@@ -2807,7 +2872,8 @@ typedef enum {
CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
- CURLINFO_LASTSOCKET = CURLINFO_LONG + 29,
+ CURLINFO_LASTSOCKET CURL_DEPRECATED(7.45.0, "Use CURLINFO_ACTIVESOCKET")
+ = CURLINFO_LONG + 29,
CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30,
CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31,
CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32,
@@ -2821,12 +2887,14 @@ typedef enum {
CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40,
CURLINFO_LOCAL_IP = CURLINFO_STRING + 41,
CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42,
- CURLINFO_TLS_SESSION = CURLINFO_PTR + 43,
+ CURLINFO_TLS_SESSION CURL_DEPRECATED(7.48.0, "Use CURLINFO_TLS_SSL_PTR")
+ = CURLINFO_PTR + 43,
CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44,
CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45,
CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46,
CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
- CURLINFO_PROTOCOL = CURLINFO_LONG + 48,
+ CURLINFO_PROTOCOL CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME")
+ = CURLINFO_LONG + 48,
CURLINFO_SCHEME = CURLINFO_STRING + 49,
CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50,
CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
@@ -2927,8 +2995,9 @@ typedef enum {
} CURLSHoption;
CURL_EXTERN CURLSH *curl_share_init(void);
-CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
-CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option,
+ ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
/****************************************************************************
* Structures for querying information about the curl library at runtime.
@@ -2945,6 +3014,7 @@ typedef enum {
CURLVERSION_EIGHTH,
CURLVERSION_NINTH,
CURLVERSION_TENTH,
+ CURLVERSION_ELEVENTH,
CURLVERSION_LAST /* never actually use this */
} CURLversion;
@@ -2953,7 +3023,7 @@ typedef enum {
meant to be a built-in version number for what kind of struct the caller
expects. If the struct ever changes, we redefine the NOW to another enum
from above. */
-#define CURLVERSION_NOW CURLVERSION_TENTH
+#define CURLVERSION_NOW CURLVERSION_ELEVENTH
struct curl_version_info_data {
CURLversion age; /* age of the returned struct */
@@ -3009,6 +3079,10 @@ struct curl_version_info_data {
/* These fields were added in CURLVERSION_TENTH */
const char *gsasl_version; /* human readable string. */
+
+ /* These fields were added in CURLVERSION_ELEVENTH */
+ /* feature_names is terminated by an entry with a NULL feature name */
+ const char * const *feature_names;
};
typedef struct curl_version_info_data curl_version_info_data;
@@ -3102,7 +3176,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
#ifdef __cplusplus
-}
+} /* end of extern "C" */
#endif
/* unfortunately, the easy.h and multi.h include files need options and info
@@ -3131,6 +3205,6 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
#endif
#endif /* __STDC__ >= 1 */
-#endif /* gcc >= 4.3 && !__cplusplus */
+#endif /* gcc >= 4.3 && !__cplusplus && !CURL_DISABLE_TYPECHECK */
#endif /* CURLINC_CURL_H */
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index 9eb5067..94db4cd 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -32,12 +32,12 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "7.86.0"
+#define LIBCURL_VERSION "7.87.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 86
+#define LIBCURL_VERSION_MINOR 87
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
@@ -59,7 +59,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
-#define LIBCURL_VERSION_NUM 0x075600
+#define LIBCURL_VERSION_NUM 0x075700
/*
* This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/easy.h b/Utilities/cmcurl/include/curl/easy.h
index 9c7e63a..98ee888 100644
--- a/Utilities/cmcurl/include/curl/easy.h
+++ b/Utilities/cmcurl/include/curl/easy.h
@@ -119,7 +119,7 @@ CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl);
#ifdef __cplusplus
-}
+} /* end of extern "C" */
#endif
#endif
diff --git a/Utilities/cmcurl/include/curl/mprintf.h b/Utilities/cmcurl/include/curl/mprintf.h
index cb948dc..06ef5c6 100644
--- a/Utilities/cmcurl/include/curl/mprintf.h
+++ b/Utilities/cmcurl/include/curl/mprintf.h
@@ -46,7 +46,7 @@ CURL_EXTERN char *curl_maprintf(const char *format, ...);
CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
#ifdef __cplusplus
-}
+} /* end of extern "C" */
#endif
#endif /* CURLINC_MPRINTF_H */
diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h
index 2f3ec37..c956d28 100644
--- a/Utilities/cmcurl/include/curl/multi.h
+++ b/Utilities/cmcurl/include/curl/multi.h
@@ -318,16 +318,16 @@ typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
void *userp); /* private callback
pointer */
-CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
- int *running_handles);
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles);
CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
curl_socket_t s,
int ev_bitmask,
int *running_handles);
-CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
- int *running_handles);
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket_all(CURLM *multi_handle, int *running_handles);
#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
/* This macro below was added in 7.16.3 to push users who recompile to use
diff --git a/Utilities/cmcurl/include/curl/system.h b/Utilities/cmcurl/include/curl/system.h
index 8d56b8a..11db51e 100644
--- a/Utilities/cmcurl/include/curl/system.h
+++ b/Utilities/cmcurl/include/curl/system.h
@@ -164,13 +164,33 @@
# endif
# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
-#elif defined(__MWERKS__)
+#elif defined(macintosh)
+# include <ConditionalMacros.h>
+# if TYPE_LONGLONG
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# else
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__TANDEM)
+# if ! defined(__LP64)
+ /* Required for 32-bit NonStop builds only. */
# define CURL_TYPEOF_CURL_OFF_T long long
# define CURL_FORMAT_CURL_OFF_T "lld"
# define CURL_FORMAT_CURL_OFF_TU "llu"
# define CURL_SUFFIX_CURL_OFF_T LL
# define CURL_SUFFIX_CURL_OFF_TU ULL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# endif
#elif defined(_WIN32_WCE)
# define CURL_TYPEOF_CURL_OFF_T __int64
diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h
index 2dabcb4..bf655bb 100644
--- a/Utilities/cmcurl/include/curl/typecheck-gcc.h
+++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h
@@ -42,107 +42,113 @@
*/
#define curl_easy_setopt(handle, option, value) \
__extension__({ \
- __typeof__(option) _curl_opt = option; \
+ CURL_IGNORE_DEPRECATION(__typeof__(option) _curl_opt = option;) \
if(__builtin_constant_p(_curl_opt)) { \
- if(curlcheck_long_option(_curl_opt)) \
- if(!curlcheck_long(value)) \
- _curl_easy_setopt_err_long(); \
- if(curlcheck_off_t_option(_curl_opt)) \
- if(!curlcheck_off_t(value)) \
- _curl_easy_setopt_err_curl_off_t(); \
- if(curlcheck_string_option(_curl_opt)) \
- if(!curlcheck_string(value)) \
- _curl_easy_setopt_err_string(); \
- if(curlcheck_write_cb_option(_curl_opt)) \
- if(!curlcheck_write_cb(value)) \
- _curl_easy_setopt_err_write_callback(); \
- if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \
- if(!curlcheck_resolver_start_callback(value)) \
- _curl_easy_setopt_err_resolver_start_callback(); \
- if((_curl_opt) == CURLOPT_READFUNCTION) \
- if(!curlcheck_read_cb(value)) \
- _curl_easy_setopt_err_read_cb(); \
- if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
- if(!curlcheck_ioctl_cb(value)) \
- _curl_easy_setopt_err_ioctl_cb(); \
- if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
- if(!curlcheck_sockopt_cb(value)) \
- _curl_easy_setopt_err_sockopt_cb(); \
- if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
- if(!curlcheck_opensocket_cb(value)) \
- _curl_easy_setopt_err_opensocket_cb(); \
- if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
- if(!curlcheck_progress_cb(value)) \
- _curl_easy_setopt_err_progress_cb(); \
- if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
- if(!curlcheck_debug_cb(value)) \
- _curl_easy_setopt_err_debug_cb(); \
- if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
- if(!curlcheck_ssl_ctx_cb(value)) \
- _curl_easy_setopt_err_ssl_ctx_cb(); \
- if(curlcheck_conv_cb_option(_curl_opt)) \
- if(!curlcheck_conv_cb(value)) \
- _curl_easy_setopt_err_conv_cb(); \
- if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
- if(!curlcheck_seek_cb(value)) \
- _curl_easy_setopt_err_seek_cb(); \
- if(curlcheck_cb_data_option(_curl_opt)) \
- if(!curlcheck_cb_data(value)) \
- _curl_easy_setopt_err_cb_data(); \
- if((_curl_opt) == CURLOPT_ERRORBUFFER) \
- if(!curlcheck_error_buffer(value)) \
- _curl_easy_setopt_err_error_buffer(); \
- if((_curl_opt) == CURLOPT_STDERR) \
- if(!curlcheck_FILE(value)) \
- _curl_easy_setopt_err_FILE(); \
- if(curlcheck_postfields_option(_curl_opt)) \
- if(!curlcheck_postfields(value)) \
- _curl_easy_setopt_err_postfields(); \
- if((_curl_opt) == CURLOPT_HTTPPOST) \
- if(!curlcheck_arr((value), struct curl_httppost)) \
- _curl_easy_setopt_err_curl_httpost(); \
- if((_curl_opt) == CURLOPT_MIMEPOST) \
- if(!curlcheck_ptr((value), curl_mime)) \
- _curl_easy_setopt_err_curl_mimepost(); \
- if(curlcheck_slist_option(_curl_opt)) \
- if(!curlcheck_arr((value), struct curl_slist)) \
- _curl_easy_setopt_err_curl_slist(); \
- if((_curl_opt) == CURLOPT_SHARE) \
- if(!curlcheck_ptr((value), CURLSH)) \
- _curl_easy_setopt_err_CURLSH(); \
+ (void) option; \
+ CURL_IGNORE_DEPRECATION( \
+ if(curlcheck_long_option(_curl_opt)) \
+ if(!curlcheck_long(value)) \
+ _curl_easy_setopt_err_long(); \
+ if(curlcheck_off_t_option(_curl_opt)) \
+ if(!curlcheck_off_t(value)) \
+ _curl_easy_setopt_err_curl_off_t(); \
+ if(curlcheck_string_option(_curl_opt)) \
+ if(!curlcheck_string(value)) \
+ _curl_easy_setopt_err_string(); \
+ if(curlcheck_write_cb_option(_curl_opt)) \
+ if(!curlcheck_write_cb(value)) \
+ _curl_easy_setopt_err_write_callback(); \
+ if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \
+ if(!curlcheck_resolver_start_callback(value)) \
+ _curl_easy_setopt_err_resolver_start_callback(); \
+ if((_curl_opt) == CURLOPT_READFUNCTION) \
+ if(!curlcheck_read_cb(value)) \
+ _curl_easy_setopt_err_read_cb(); \
+ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
+ if(!curlcheck_ioctl_cb(value)) \
+ _curl_easy_setopt_err_ioctl_cb(); \
+ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
+ if(!curlcheck_sockopt_cb(value)) \
+ _curl_easy_setopt_err_sockopt_cb(); \
+ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
+ if(!curlcheck_opensocket_cb(value)) \
+ _curl_easy_setopt_err_opensocket_cb(); \
+ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
+ if(!curlcheck_progress_cb(value)) \
+ _curl_easy_setopt_err_progress_cb(); \
+ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
+ if(!curlcheck_debug_cb(value)) \
+ _curl_easy_setopt_err_debug_cb(); \
+ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
+ if(!curlcheck_ssl_ctx_cb(value)) \
+ _curl_easy_setopt_err_ssl_ctx_cb(); \
+ if(curlcheck_conv_cb_option(_curl_opt)) \
+ if(!curlcheck_conv_cb(value)) \
+ _curl_easy_setopt_err_conv_cb(); \
+ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
+ if(!curlcheck_seek_cb(value)) \
+ _curl_easy_setopt_err_seek_cb(); \
+ if(curlcheck_cb_data_option(_curl_opt)) \
+ if(!curlcheck_cb_data(value)) \
+ _curl_easy_setopt_err_cb_data(); \
+ if((_curl_opt) == CURLOPT_ERRORBUFFER) \
+ if(!curlcheck_error_buffer(value)) \
+ _curl_easy_setopt_err_error_buffer(); \
+ if((_curl_opt) == CURLOPT_STDERR) \
+ if(!curlcheck_FILE(value)) \
+ _curl_easy_setopt_err_FILE(); \
+ if(curlcheck_postfields_option(_curl_opt)) \
+ if(!curlcheck_postfields(value)) \
+ _curl_easy_setopt_err_postfields(); \
+ if((_curl_opt) == CURLOPT_HTTPPOST) \
+ if(!curlcheck_arr((value), struct curl_httppost)) \
+ _curl_easy_setopt_err_curl_httpost(); \
+ if((_curl_opt) == CURLOPT_MIMEPOST) \
+ if(!curlcheck_ptr((value), curl_mime)) \
+ _curl_easy_setopt_err_curl_mimepost(); \
+ if(curlcheck_slist_option(_curl_opt)) \
+ if(!curlcheck_arr((value), struct curl_slist)) \
+ _curl_easy_setopt_err_curl_slist(); \
+ if((_curl_opt) == CURLOPT_SHARE) \
+ if(!curlcheck_ptr((value), CURLSH)) \
+ _curl_easy_setopt_err_CURLSH(); \
+ ) \
} \
curl_easy_setopt(handle, _curl_opt, value); \
})
/* wraps curl_easy_getinfo() with typechecking */
#define curl_easy_getinfo(handle, info, arg) \
- __extension__({ \
- __typeof__(info) _curl_info = info; \
+ __extension__({ \
+ CURL_IGNORE_DEPRECATION(__typeof__(info) _curl_info = info;) \
if(__builtin_constant_p(_curl_info)) { \
- if(curlcheck_string_info(_curl_info)) \
- if(!curlcheck_arr((arg), char *)) \
- _curl_easy_getinfo_err_string(); \
- if(curlcheck_long_info(_curl_info)) \
- if(!curlcheck_arr((arg), long)) \
- _curl_easy_getinfo_err_long(); \
- if(curlcheck_double_info(_curl_info)) \
- if(!curlcheck_arr((arg), double)) \
- _curl_easy_getinfo_err_double(); \
- if(curlcheck_slist_info(_curl_info)) \
- if(!curlcheck_arr((arg), struct curl_slist *)) \
- _curl_easy_getinfo_err_curl_slist(); \
- if(curlcheck_tlssessioninfo_info(_curl_info)) \
- if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \
- _curl_easy_getinfo_err_curl_tlssesssioninfo(); \
- if(curlcheck_certinfo_info(_curl_info)) \
- if(!curlcheck_arr((arg), struct curl_certinfo *)) \
- _curl_easy_getinfo_err_curl_certinfo(); \
- if(curlcheck_socket_info(_curl_info)) \
- if(!curlcheck_arr((arg), curl_socket_t)) \
- _curl_easy_getinfo_err_curl_socket(); \
- if(curlcheck_off_t_info(_curl_info)) \
- if(!curlcheck_arr((arg), curl_off_t)) \
- _curl_easy_getinfo_err_curl_off_t(); \
+ (void) info; \
+ CURL_IGNORE_DEPRECATION( \
+ if(curlcheck_string_info(_curl_info)) \
+ if(!curlcheck_arr((arg), char *)) \
+ _curl_easy_getinfo_err_string(); \
+ if(curlcheck_long_info(_curl_info)) \
+ if(!curlcheck_arr((arg), long)) \
+ _curl_easy_getinfo_err_long(); \
+ if(curlcheck_double_info(_curl_info)) \
+ if(!curlcheck_arr((arg), double)) \
+ _curl_easy_getinfo_err_double(); \
+ if(curlcheck_slist_info(_curl_info)) \
+ if(!curlcheck_arr((arg), struct curl_slist *)) \
+ _curl_easy_getinfo_err_curl_slist(); \
+ if(curlcheck_tlssessioninfo_info(_curl_info)) \
+ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \
+ _curl_easy_getinfo_err_curl_tlssesssioninfo(); \
+ if(curlcheck_certinfo_info(_curl_info)) \
+ if(!curlcheck_arr((arg), struct curl_certinfo *)) \
+ _curl_easy_getinfo_err_curl_certinfo(); \
+ if(curlcheck_socket_info(_curl_info)) \
+ if(!curlcheck_arr((arg), curl_socket_t)) \
+ _curl_easy_getinfo_err_curl_socket(); \
+ if(curlcheck_off_t_info(_curl_info)) \
+ if(!curlcheck_arr((arg), curl_off_t)) \
+ _curl_easy_getinfo_err_curl_off_t(); \
+ ) \
} \
curl_easy_getinfo(handle, _curl_info, arg); \
})
@@ -436,7 +442,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(CURLINFO_OFF_T < (info))
-/* typecheck helpers -- check whether given expression has requested type*/
+/* typecheck helpers -- check whether given expression has requested type */
/* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros,
* otherwise define a new macro. Search for __builtin_types_compatible_p
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 3138473..074ab9d 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -123,12 +123,40 @@ endif()
target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
+if(0) # This code not needed for building within CMake.
+transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
+include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
+endif()
+
set_target_properties(${LIB_NAME} PROPERTIES
COMPILE_DEFINITIONS BUILDING_LIBCURL
OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
)
if(0) # This code not needed for building within CMake.
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
+ CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+ CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
+
+ # FreeBSD comes with the a.out and elf flavours
+ # but a.out was supported up to version 3.x and
+ # elf from 3.x. I cannot imagine someone runnig
+ # CMake on those ancient systems
+ CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+
+ CMAKE_SYSTEM_NAME STREQUAL "Haiku")
+
+ math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
+ set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
+
+ set_target_properties(${LIB_NAME} PROPERTIES
+ VERSION ${CMAKEVERSION}
+ SOVERSION ${CMAKESONAME}
+ )
+
+endif()
+
+
if(HIDES_CURL_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index b2d2e9e..9eafa93 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -74,6 +74,7 @@ LIB_VTLS_HFILES = \
vtls/schannel.h \
vtls/sectransp.h \
vtls/vtls.h \
+ vtls/vtls_int.h \
vtls/wolfssl.h \
vtls/x509asn1.h
@@ -105,6 +106,7 @@ LIB_CFILES = \
base64.c \
bufref.c \
c-hyper.c \
+ cfilters.c \
conncache.c \
connect.c \
content_encoding.c \
@@ -160,7 +162,7 @@ LIB_CFILES = \
http_ntlm.c \
http_proxy.c \
http_aws_sigv4.c \
- idn_win32.c \
+ idn.c \
if2ip.c \
imap.c \
inet_ntop.c \
@@ -227,6 +229,7 @@ LIB_HFILES = \
asyn.h \
bufref.h \
c-hyper.h \
+ cfilters.h \
conncache.h \
connect.h \
content_encoding.h \
@@ -290,6 +293,7 @@ LIB_HFILES = \
http_ntlm.h \
http_proxy.h \
http_aws_sigv4.h \
+ idn.h \
if2ip.h \
imap.h \
inet_ntop.h \
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
index 7bca840..ec18e38 100644
--- a/Utilities/cmcurl/lib/altsvc.c
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -517,15 +517,21 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
dsthost = srchost;
}
if(*p == ':') {
- /* a port number */
- unsigned long port = strtoul(++p, &end_ptr, 10);
- if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
+ unsigned long port = 0;
+ p++;
+ if(ISDIGIT(*p))
+ /* a port number */
+ port = strtoul(p, &end_ptr, 10);
+ else
+ end_ptr = (char *)p; /* not left uninitialized */
+ if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
infof(data, "Unknown alt-svc port number, ignoring.");
valid = FALSE;
}
- else
+ else {
dstport = curlx_ultous(port);
- p = end_ptr;
+ p = end_ptr;
+ }
}
if(*p++ != '\"')
break;
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 33edba1..4436da3 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -47,15 +47,6 @@
#include <inet.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
index 8b375eb..705f0f6 100644
--- a/Utilities/cmcurl/lib/asyn-thread.c
+++ b/Utilities/cmcurl/lib/asyn-thread.c
@@ -44,19 +44,8 @@
#include <inet.h>
#endif
-#if defined(USE_THREADS_POSIX)
-# ifdef HAVE_PTHREAD_H
-# include <pthread.h>
-# endif
-#elif defined(USE_THREADS_WIN32)
-# ifdef HAVE_PROCESS_H
-# include <process.h>
-# endif
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
+#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
+# include <pthread.h>
#endif
#ifdef HAVE_GETADDRINFO
@@ -75,7 +64,6 @@
#include "inet_ntop.h"
#include "curl_threads.h"
#include "connect.h"
-#include "socketpair.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -541,7 +529,8 @@ void Curl_resolver_kill(struct Curl_easy *data)
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
- if(td && td->thread_hnd != curl_thread_t_null)
+ if(td && td->thread_hnd != curl_thread_t_null
+ && (data->set.quick_exit != 1L))
(void)thread_wait_resolv(data, NULL, FALSE);
else
Curl_resolver_cancel(data);
diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c
index 52654c2..bacd627 100644
--- a/Utilities/cmcurl/lib/base64.c
+++ b/Utilities/cmcurl/lib/base64.c
@@ -37,8 +37,7 @@
#include "warnless.h"
#include "curl_base64.h"
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
+/* The last 2 #include files should be in this order */
#include "curl_memory.h"
#include "memdebug.h"
@@ -52,39 +51,12 @@ static const char base64[]=
static const char base64url[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-static size_t decodeQuantum(unsigned char *dest, const char *src)
-{
- size_t padding = 0;
- const char *s;
- unsigned long i, x = 0;
-
- for(i = 0, s = src; i < 4; i++, s++) {
- if(*s == '=') {
- x <<= 6;
- padding++;
- }
- else {
- const char *p = strchr(base64, *s);
- if(p)
- x = (x << 6) + curlx_uztoul(p - base64);
- else
- return 0;
- }
- }
-
- if(padding < 1)
- dest[2] = curlx_ultouc(x & 0xFFUL);
-
- x >>= 8;
- if(padding < 2)
- dest[1] = curlx_ultouc(x & 0xFFUL);
-
- x >>= 8;
- dest[0] = curlx_ultouc(x & 0xFFUL);
-
- return 3 - padding;
-}
-
+static const unsigned char decodetable[] =
+{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255,
+ 255, 255, 255, 255, 0, 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, 255, 255, 255, 255, 255, 255, 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 };
/*
* Curl_base64_decode()
*
@@ -106,10 +78,11 @@ CURLcode Curl_base64_decode(const char *src,
size_t padding = 0;
size_t i;
size_t numQuantums;
+ size_t fullQuantums;
size_t rawlen = 0;
- const char *padptr;
unsigned char *pos;
unsigned char *newstr;
+ unsigned char lookup[256];
*outptr = NULL;
*outlen = 0;
@@ -119,21 +92,18 @@ CURLcode Curl_base64_decode(const char *src,
if(!srclen || srclen % 4)
return CURLE_BAD_CONTENT_ENCODING;
- /* Find the position of any = padding characters */
- padptr = strchr(src, '=');
- if(padptr) {
+ /* srclen is at least 4 here */
+ while(src[srclen - 1 - padding] == '=') {
+ /* count padding characters */
padding++;
/* A maximum of two = padding characters is allowed */
- if(padptr[1] == '=')
- padding++;
-
- /* Check the = padding characters weren't part way through the input */
- if(padptr + padding != src + srclen)
+ if(padding > 2)
return CURLE_BAD_CONTENT_ENCODING;
}
/* Calculate the number of quantums */
numQuantums = srclen / 4;
+ fullQuantums = numQuantums - (padding ? 1 : 0);
/* Calculate the size of the decoded string */
rawlen = (numQuantums * 3) - padding;
@@ -145,17 +115,59 @@ CURLcode Curl_base64_decode(const char *src,
pos = newstr;
- /* Decode the quantums */
- for(i = 0; i < numQuantums; i++) {
- size_t result = decodeQuantum(pos, src);
- if(!result) {
- free(newstr);
-
- return CURLE_BAD_CONTENT_ENCODING;
+ memset(lookup, 0xff, sizeof(lookup));
+ memcpy(&lookup['+'], decodetable, sizeof(decodetable));
+ /* replaces
+ {
+ unsigned char c;
+ const unsigned char *p = (const unsigned char *)base64;
+ for(c = 0; *p; c++, p++)
+ lookup[*p] = c;
+ }
+ */
+
+ /* Decode the complete quantums first */
+ for(i = 0; i < fullQuantums; i++) {
+ unsigned char val;
+ unsigned int x = 0;
+ int j;
+
+ for(j = 0; j < 4; j++) {
+ val = lookup[(unsigned char)*src++];
+ if(val == 0xff) /* bad symbol */
+ goto bad;
+ x = (x << 6) | val;
}
-
- pos += result;
- src += 4;
+ pos[2] = x & 0xff;
+ pos[1] = (x >> 8) & 0xff;
+ pos[0] = (x >> 16) & 0xff;
+ pos += 3;
+ }
+ if(padding) {
+ /* this means either 8 or 16 bits output */
+ unsigned char val;
+ unsigned int x = 0;
+ int j;
+ size_t padc = 0;
+ for(j = 0; j < 4; j++) {
+ if(*src == '=') {
+ x <<= 6;
+ src++;
+ if(++padc > padding)
+ /* this is a badly placed '=' symbol! */
+ goto bad;
+ }
+ else {
+ val = lookup[(unsigned char)*src++];
+ if(val == 0xff) /* bad symbol */
+ goto bad;
+ x = (x << 6) | val;
+ }
+ }
+ if(padding == 1)
+ pos[1] = (x >> 8) & 0xff;
+ pos[0] = (x >> 16) & 0xff;
+ pos += 3 - padding;
}
/* Zero terminate */
@@ -166,81 +178,60 @@ CURLcode Curl_base64_decode(const char *src,
*outlen = rawlen;
return CURLE_OK;
+ bad:
+ free(newstr);
+ return CURLE_BAD_CONTENT_ENCODING;
}
static CURLcode base64_encode(const char *table64,
const char *inputbuff, size_t insize,
char **outptr, size_t *outlen)
{
- unsigned char ibuf[3];
- unsigned char obuf[4];
- int i;
- int inputparts;
char *output;
char *base64data;
- const char *indata = inputbuff;
+ const unsigned char *in = (unsigned char *)inputbuff;
const char *padstr = &table64[64]; /* Point to padding string. */
*outptr = NULL;
*outlen = 0;
if(!insize)
- insize = strlen(indata);
+ insize = strlen(inputbuff);
#if SIZEOF_SIZE_T == 4
if(insize > UINT_MAX/4)
return CURLE_OUT_OF_MEMORY;
#endif
- base64data = output = malloc(insize * 4 / 3 + 4);
+ base64data = output = malloc((insize + 2) / 3 * 4 + 1);
if(!output)
return CURLE_OUT_OF_MEMORY;
- while(insize > 0) {
- for(i = inputparts = 0; i < 3; i++) {
- if(insize > 0) {
- inputparts++;
- ibuf[i] = (unsigned char) *indata;
- indata++;
- insize--;
+ while(insize >= 3) {
+ *output++ = table64[ in[0] >> 2 ];
+ *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ];
+ *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ];
+ *output++ = table64[ in[2] & 0x3F ];
+ insize -= 3;
+ in += 3;
+ }
+ if(insize) {
+ /* this is only one or two bytes now */
+ *output++ = table64[ in[0] >> 2 ];
+ if(insize == 1) {
+ *output++ = table64[ ((in[0] & 0x03) << 4) ];
+ if(*padstr) {
+ *output++ = *padstr;
+ *output++ = *padstr;
}
- else
- ibuf[i] = 0;
}
-
- obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
- obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
- ((ibuf[1] & 0xF0) >> 4));
- obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
- ((ibuf[2] & 0xC0) >> 6));
- obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
-
- switch(inputparts) {
- case 1: /* only one byte read */
- i = msnprintf(output, 5, "%c%c%s%s",
- table64[obuf[0]],
- table64[obuf[1]],
- padstr,
- padstr);
- break;
-
- case 2: /* two bytes read */
- i = msnprintf(output, 5, "%c%c%c%s",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]],
- padstr);
- break;
-
- default:
- i = msnprintf(output, 5, "%c%c%c%c",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]],
- table64[obuf[3]]);
- break;
+ else {
+ /* insize == 2 */
+ *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ];
+ *output++ = table64[ ((in[1] & 0x0F) << 2) ];
+ if(*padstr)
+ *output++ = *padstr;
}
- output += i;
}
/* Zero terminate */
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index 86abcdb..65f5581 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -163,6 +163,10 @@ static int hyper_each_header(void *userdata,
writetype = CLIENTWRITE_HEADER;
if(data->set.include_header)
writetype |= CLIENTWRITE_BODY;
+ if(data->state.hconnect)
+ writetype |= CLIENTWRITE_CONNECT;
+ if(data->req.httpcode/100 == 1)
+ writetype |= CLIENTWRITE_1XX;
result = Curl_client_write(data, writetype, headp, len);
if(result) {
data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
@@ -170,8 +174,8 @@ static int hyper_each_header(void *userdata,
}
}
- data->info.header_size += (long)len;
- data->req.headerbytecount += (long)len;
+ data->info.header_size += (curl_off_t)len;
+ data->req.headerbytecount += (curl_off_t)len;
return HYPER_ITER_CONTINUE;
}
@@ -245,7 +249,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
}
/*
- * Hyper does not consider the status line, the first line in a HTTP/1
+ * Hyper does not consider the status line, the first line in an HTTP/1
* response, to be a header. The libcurl API does. This function sends the
* status line in the header callback. */
static CURLcode status_line(struct Curl_easy *data,
@@ -260,23 +264,25 @@ static CURLcode status_line(struct Curl_easy *data,
int writetype;
vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
(http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
- conn->httpversion =
- http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
- (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
- if(http_version == HYPER_HTTP_VERSION_1_0)
- data->state.httpwant = CURL_HTTP_VERSION_1_0;
-
- if(data->state.hconnect)
- /* CONNECT */
- data->info.httpproxycode = http_status;
/* We need to set 'httpcodeq' for functions that check the response code in
a single place. */
data->req.httpcode = http_status;
- result = Curl_http_statusline(data, conn);
- if(result)
- return result;
+ if(data->state.hconnect)
+ /* CONNECT */
+ data->info.httpproxycode = http_status;
+ else {
+ conn->httpversion =
+ http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
+ (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+ if(http_version == HYPER_HTTP_VERSION_1_0)
+ data->state.httpwant = CURL_HTTP_VERSION_1_0;
+
+ result = Curl_http_statusline(data, conn);
+ if(result)
+ return result;
+ }
Curl_dyn_reset(&data->state.headerb);
@@ -299,9 +305,8 @@ static CURLcode status_line(struct Curl_easy *data,
if(result)
return result;
}
- data->info.header_size += (long)len;
- data->req.headerbytecount += (long)len;
- data->req.httpcode = http_status;
+ data->info.header_size += (curl_off_t)len;
+ data->req.headerbytecount += (curl_off_t)len;
return CURLE_OK;
}
@@ -415,8 +420,10 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
break;
}
else if(h->endtask == task) {
- /* end of transfer */
+ /* end of transfer, forget the task handled, we might get a
+ * new one with the same address in the future. */
*done = TRUE;
+ h->endtask = NULL;
infof(data, "hyperstream is done");
if(!k->bodywrites) {
/* hyper doesn't always call the body write callback */
@@ -679,7 +686,7 @@ static int uploadpostfields(void *userdata, hyper_context *ctx,
return HYPER_POLL_ERROR;
}
/* increasing the writebytecount here is a little premature but we
- don't know exactly when the body is sent*/
+ don't know exactly when the body is sent */
data->req.writebytecount += (size_t)data->req.p.http->postsize;
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
data->req.upload_done = TRUE;
@@ -692,6 +699,7 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
{
size_t fillcount;
struct Curl_easy *data = (struct Curl_easy *)userdata;
+ struct connectdata *conn = (struct connectdata *)data->conn;
CURLcode result;
(void)ctx;
@@ -706,7 +714,15 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
return HYPER_POLL_PENDING;
}
- result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ fillcount = 0;
+ data->req.upload_chunky = FALSE;
+ result = CURLE_OK;
+ }
+ else {
+ result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
+ &fillcount);
+ }
if(result) {
data->state.hresult = result;
return HYPER_POLL_ERROR;
@@ -732,7 +748,7 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
return HYPER_POLL_ERROR;
}
/* increasing the writebytecount here is a little premature but we
- don't know exactly when the body is sent*/
+ don't know exactly when the body is sent */
data->req.writebytecount += fillcount;
Curl_pgrsSetUploadCounter(data, fillcount);
}
@@ -740,7 +756,7 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
}
/*
- * bodysend() sets up headers in the outgoing request for a HTTP transfer that
+ * bodysend() sets up headers in the outgoing request for an HTTP transfer that
* sends a body
*/
@@ -845,7 +861,7 @@ static void http1xx_cb(void *arg, struct hyper_response *resp)
}
/*
- * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * Curl_http() gets called from the generic multi_do() function when an HTTP
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
@@ -1159,7 +1175,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
- data->req.upload_chunky = FALSE;
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ data->req.upload_chunky = TRUE;
+ }
+ else {
+ data->req.upload_chunky = FALSE;
+ }
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c
new file mode 100644
index 0000000..bcb33da
--- /dev/null
+++ b/Utilities/cmcurl/lib/cfilters.c
@@ -0,0 +1,502 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "strerror.h"
+#include "cfilters.h"
+#include "connect.h"
+#include "url.h" /* for Curl_safefree() */
+#include "sendf.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "progress.h"
+#include "warnless.h"
+#include "http_proxy.h"
+#include "socks.h"
+#include "vtls/vtls.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+
+void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ (void)cf;
+ (void)data;
+}
+
+CURLcode Curl_cf_def_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct Curl_dns_entry *remotehost)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->setup(cf->next, data, remotehost);
+}
+
+void Curl_cf_def_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ (void)cf;
+ (void)data;
+}
+
+void Curl_cf_def_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ (void)cf;
+ (void)data;
+}
+
+void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ DEBUGASSERT(cf->next);
+ cf->connected = FALSE;
+ cf->next->cft->close(cf->next, data);
+}
+
+CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->connect(cf->next, data, blocking, done);
+}
+
+void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const char **phost, const char **pdisplay_host,
+ int *pport)
+{
+ DEBUGASSERT(cf->next);
+ cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+}
+
+int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->get_select_socks(cf->next, data, socks);
+}
+
+bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->has_data_pending(cf->next, data);
+}
+
+ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *buf, size_t len, CURLcode *err)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->do_send(cf->next, data, buf, len, err);
+}
+
+ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *err)
+{
+ DEBUGASSERT(cf->next);
+ return cf->next->cft->do_recv(cf->next, data, buf, len, err);
+}
+
+void Curl_conn_cf_discard_all(struct Curl_easy *data,
+ struct connectdata *conn, int index)
+{
+ struct Curl_cfilter *cfn, *cf = conn->cfilter[index];
+
+ if(cf) {
+ conn->cfilter[index] = NULL;
+ while(cf) {
+ cfn = cf->next;
+ cf->cft->destroy(cf, data);
+ free(cf);
+ cf = cfn;
+ }
+ }
+}
+
+void Curl_conn_close(struct Curl_easy *data, int index)
+{
+ struct Curl_cfilter *cf;
+
+ DEBUGASSERT(data->conn);
+ /* it is valid to call that without filters being present */
+ cf = data->conn->cfilter[index];
+ if(cf) {
+ cf->cft->close(cf, data);
+ }
+}
+
+ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
+ size_t len, CURLcode *code)
+{
+ struct Curl_cfilter *cf;
+ ssize_t nread;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ cf = data->conn->cfilter[num];
+ while(cf && !cf->connected) {
+ cf = cf->next;
+ }
+ if(cf) {
+ nread = cf->cft->do_recv(cf, data, buf, len, code);
+ /* DEBUGF(infof(data, "Curl_conn_recv(handle=%p, index=%d)"
+ "-> %ld, err=%d", data, num, nread, *code));*/
+ return nread;
+ }
+ failf(data, "no filter connected, conn=%ld, sockindex=%d",
+ data->conn->connection_id, num);
+ *code = CURLE_FAILED_INIT;
+ return -1;
+}
+
+ssize_t Curl_conn_send(struct Curl_easy *data, int num,
+ const void *mem, size_t len, CURLcode *code)
+{
+ struct Curl_cfilter *cf;
+ ssize_t nwritten;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ cf = data->conn->cfilter[num];
+ while(cf && !cf->connected) {
+ cf = cf->next;
+ }
+ if(cf) {
+ nwritten = cf->cft->do_send(cf, data, mem, len, code);
+ /* DEBUGF(infof(data, "Curl_conn_send(handle=%p, index=%d, len=%ld)"
+ " -> %ld, err=%d", data, num, len, nwritten, *code));*/
+ return nwritten;
+ }
+ failf(data, "no filter connected, conn=%ld, sockindex=%d",
+ data->conn->connection_id, num);
+ *code = CURLE_FAILED_INIT;
+ return -1;
+}
+
+CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
+ const struct Curl_cftype *cft,
+ void *ctx)
+{
+ struct Curl_cfilter *cf;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+
+ DEBUGASSERT(cft);
+ cf = calloc(sizeof(*cf), 1);
+ if(!cf)
+ goto out;
+
+ cf->cft = cft;
+ cf->ctx = ctx;
+ result = CURLE_OK;
+out:
+ *pcf = cf;
+ return result;
+}
+
+void Curl_conn_cf_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int index,
+ struct Curl_cfilter *cf)
+{
+ (void)data;
+ DEBUGASSERT(conn);
+ DEBUGASSERT(!cf->conn);
+ DEBUGASSERT(!cf->next);
+
+ DEBUGF(infof(data, CMSGI(conn, index, "cf_add(filter=%s)"),
+ cf->cft->name));
+ cf->next = conn->cfilter[index];
+ cf->conn = conn;
+ cf->sockindex = index;
+ conn->cfilter[index] = cf;
+}
+
+void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex];
+
+ /* remove from chain if still in there */
+ DEBUGASSERT(cf);
+ while (*pprev) {
+ if (*pprev == cf) {
+ *pprev = cf->next;
+ break;
+ }
+ pprev = &((*pprev)->next);
+ }
+ cf->cft->destroy(cf, data);
+ free(cf);
+}
+
+ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *buf, size_t len, CURLcode *err)
+{
+ return cf->cft->do_send(cf, data, buf, len, err);
+}
+
+ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *err)
+{
+ return cf->cft->do_recv(cf, data, buf, len, err);
+}
+
+CURLcode Curl_conn_setup(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ const struct Curl_dns_entry *remotehost,
+ int ssl_mode)
+{
+ struct Curl_cfilter *cf;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+ /* If no filter is set, we have the "default" setup of connection filters.
+ * The filter chain from botton to top will be:
+ * - SOCKET socket filter for outgoing connection to remotehost
+ * if http_proxy tunneling is engaged:
+ * - SSL if proxytype is CURLPROXY_HTTPS
+ * - HTTP_PROXY_TUNNEL
+ * otherwise, if socks_proxy is engaged:
+ * - SOCKS_PROXY_TUNNEL
+ * - SSL if conn->handler has PROTOPT_SSL
+ */
+ if(!conn->cfilter[sockindex]) {
+ DEBUGF(infof(data, DMSGI(data, sockindex, "setup, init filter chain")));
+ result = Curl_conn_socket_set(data, conn, sockindex);
+ if(result)
+ goto out;
+
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.socksproxy) {
+ result = Curl_conn_socks_proxy_add(data, conn, sockindex);
+ if(result)
+ goto out;
+ }
+
+ if(conn->bits.httpproxy) {
+#ifdef USE_SSL
+ if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
+ result = Curl_ssl_cfilter_proxy_add(data, conn, sockindex);
+ if(result)
+ goto out;
+ }
+#endif /* USE_SSL */
+
+#if !defined(CURL_DISABLE_HTTP)
+ if(conn->bits.tunnel_proxy) {
+ result = Curl_conn_http_proxy_add(data, conn, sockindex);
+ if(result)
+ goto out;
+ }
+#endif /* !CURL_DISABLE_HTTP */
+ }
+#endif /* !CURL_DISABLE_PROXY */
+
+#ifdef USE_SSL
+ if(ssl_mode == CURL_CF_SSL_ENABLE
+ || (ssl_mode != CURL_CF_SSL_DISABLE
+ && conn->handler->flags & PROTOPT_SSL)) {
+ result = Curl_ssl_cfilter_add(data, conn, sockindex);
+ if(result)
+ goto out;
+ }
+#else
+ (void)ssl_mode;
+#endif /* USE_SSL */
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+ if(data->set.haproxyprotocol) {
+ result = Curl_conn_haproxy_add(data, conn, sockindex);
+ if(result)
+ goto out;
+ }
+#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
+
+ }
+ DEBUGASSERT(conn->cfilter[sockindex]);
+ cf = data->conn->cfilter[sockindex];
+ result = cf->cft->setup(cf, data, remotehost);
+
+out:
+ return result;
+}
+
+CURLcode Curl_conn_connect(struct Curl_easy *data,
+ int sockindex,
+ bool blocking,
+ bool *done)
+{
+ struct Curl_cfilter *cf;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+
+ cf = data->conn->cfilter[sockindex];
+ DEBUGASSERT(cf);
+ result = cf->cft->connect(cf, data, blocking, done);
+
+ DEBUGF(infof(data, DMSGI(data, sockindex, "connect(block=%d)-> %d, done=%d"),
+ blocking, result, *done));
+ return result;
+}
+
+bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ cf = conn->cfilter[sockindex];
+ return cf && cf->connected;
+}
+
+bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ cf = data->conn->cfilter[sockindex];
+ while(cf) {
+ if(cf->connected)
+ return TRUE;
+ if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+ return FALSE;
+ cf = cf->next;
+ }
+ return FALSE;
+}
+
+bool Curl_conn_is_ssl(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf = data->conn? data->conn->cfilter[sockindex] : NULL;
+
+ (void)data;
+ for(; cf; cf = cf->next) {
+ if(cf->cft->flags & CF_TYPE_SSL)
+ return TRUE;
+ if(cf->cft->flags & CF_TYPE_IP_CONNECT)
+ return FALSE;
+ }
+ return FALSE;
+}
+
+
+bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ (void)data;
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ if(Curl_recv_has_postponed_data(data->conn, sockindex))
+ return TRUE;
+
+ cf = data->conn->cfilter[sockindex];
+ while(cf && !cf->connected) {
+ cf = cf->next;
+ }
+ if(cf) {
+ return cf->cft->has_data_pending(cf, data);
+ }
+ return FALSE;
+}
+
+int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
+ curl_socket_t *socks)
+{
+ struct Curl_cfilter *cf;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ cf = data->conn->cfilter[sockindex];
+ if(cf) {
+ return cf->cft->get_select_socks(cf, data, socks);
+ }
+ return GETSOCK_BLANK;
+}
+
+void Curl_conn_attach_data(struct connectdata *conn,
+ struct Curl_easy *data)
+{
+ size_t i;
+ struct Curl_cfilter *cf;
+
+ for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+ cf = conn->cfilter[i];
+ if(cf) {
+ while(cf) {
+ cf->cft->attach_data(cf, data);
+ cf = cf->next;
+ }
+ }
+ }
+}
+
+void Curl_conn_detach_data(struct connectdata *conn,
+ struct Curl_easy *data)
+{
+ size_t i;
+ struct Curl_cfilter *cf;
+
+ for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+ cf = conn->cfilter[i];
+ if(cf) {
+ while(cf) {
+ cf->cft->detach_data(cf, data);
+ cf = cf->next;
+ }
+ }
+ }
+}
+
+void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
+ const char **phost, const char **pdisplay_host,
+ int *pport)
+{
+ struct Curl_cfilter *cf;
+
+ DEBUGASSERT(data->conn);
+ cf = data->conn->cfilter[sockindex];
+ if(cf) {
+ cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
+ }
+ else {
+ /* Some filter ask during shutdown for this, mainly for debugging
+ * purposes. We hand out the defaults, however this is not always
+ * accurate, as the connction might be tunneled, etc. But all that
+ * state is already gone here. */
+ *phost = data->conn->host.name;
+ *pdisplay_host = data->conn->host.dispname;
+ *pport = data->conn->remote_port;
+ }
+}
+
+
diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h
new file mode 100644
index 0000000..4b81b42
--- /dev/null
+++ b/Utilities/cmcurl/lib/cfilters.h
@@ -0,0 +1,315 @@
+#ifndef HEADER_CURL_CFILTERS_H
+#define HEADER_CURL_CFILTERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+
+struct Curl_cfilter;
+struct Curl_easy;
+struct Curl_dns_entry;
+struct connectdata;
+
+/* Callback to destroy resources held by this filter instance.
+ * Implementations MUST NOT chain calls to cf->next.
+ */
+typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/* Setup the connection for `data`, using destination `remotehost`.
+ */
+typedef CURLcode Curl_cft_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct Curl_dns_entry *remotehost);
+typedef void Curl_cft_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done);
+
+/* Return the hostname and port the connection goes to.
+ * This may change with the connection state of filters when tunneling
+ * is involved.
+ * @param cf the filter to ask
+ * @param data the easy handle currently active
+ * @param phost on return, points to the relevant, real hostname.
+ * this is owned by the connection.
+ * @param pdisplay_host on return, points to the printable hostname.
+ * this is owned by the connection.
+ * @param pport on return, contains the port number
+ */
+typedef void Curl_cft_get_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char **phost,
+ const char **pdisplay_host,
+ int *pport);
+
+/* Filters may return sockets and fdset flags they are waiting for.
+ * The passes array has room for up to MAX_SOCKSPEREASYHANDLE sockets.
+ * @return read/write fdset for index in socks
+ * or GETSOCK_BLANK when nothing to wait on
+ */
+typedef int Curl_cft_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks);
+
+typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+
+typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
+ const void *buf, /* data to write */
+ size_t len, /* amount to write */
+ CURLcode *err); /* error to return */
+
+typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
+ char *buf, /* store data here */
+ size_t len, /* amount to read */
+ CURLcode *err); /* error to return */
+
+typedef void Curl_cft_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+typedef void Curl_cft_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/**
+ * The easy handle `data` is being detached (no longer served)
+ * by connection `conn`. All filters are informed to release any resources
+ * related to `data`.
+ * Note: there may be several `data` attached to a connection at the same
+ * time.
+ */
+void Curl_conn_detach(struct connectdata *conn, struct Curl_easy *data);
+
+#define CF_TYPE_IP_CONNECT (1 << 0)
+#define CF_TYPE_SSL (1 << 1)
+
+/* A connection filter type, e.g. specific implementation. */
+struct Curl_cftype {
+ const char *name; /* name of the filter type */
+ long flags; /* flags of filter type */
+ Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
+ Curl_cft_setup *setup; /* setup for a connection */
+ Curl_cft_connect *connect; /* establish connection */
+ Curl_cft_close *close; /* close conn */
+ Curl_cft_get_host *get_host; /* host filter talks to */
+ Curl_cft_get_select_socks *get_select_socks;/* sockets to select on */
+ Curl_cft_data_pending *has_data_pending;/* conn has data pending */
+ Curl_cft_send *do_send; /* send data */
+ Curl_cft_recv *do_recv; /* receive data */
+ Curl_cft_attach_data *attach_data; /* data is being handled here */
+ Curl_cft_detach_data *detach_data; /* data is no longer handled here */
+};
+
+/* A connection filter instance, e.g. registered at a connection */
+struct Curl_cfilter {
+ const struct Curl_cftype *cft; /* the type providing implementation */
+ struct Curl_cfilter *next; /* next filter in chain */
+ void *ctx; /* filter type specific settings */
+ struct connectdata *conn; /* the connection this filter belongs to */
+ int sockindex; /* TODO: like to get rid off this */
+ BIT(connected); /* != 0 iff this filter is connected */
+};
+
+/* Default implementations for the type functions, implementing nop. */
+void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/* Default implementations for the type functions, implementing pass-through
+ * the filter chain. */
+CURLcode Curl_cf_def_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct Curl_dns_entry *remotehost);
+void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done);
+void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const char **phost, const char **pdisplay_host,
+ int *pport);
+int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks);
+bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *buf, size_t len, CURLcode *err);
+ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *err);
+void Curl_cf_def_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+void Curl_cf_def_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/**
+ * Create a new filter instance, unattached to the filter chain.
+ * Use Curl_conn_cf_add() to add it to the chain.
+ * @param pcf on success holds the created instance
+ * @parm cft the filter type
+ * @param ctx the type specific context to use
+ */
+CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
+ const struct Curl_cftype *cft,
+ void *ctx);
+
+/**
+ * Add a filter instance to the `sockindex` filter chain at connection
+ * `data->conn`. The filter must not already be attached. It is inserted at
+ * the start of the chain (top).
+ */
+void Curl_conn_cf_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_cfilter *cf);
+
+/**
+ * Remove and destroy all filters at chain `sockindex` on connection `conn`.
+ */
+void Curl_conn_cf_discard_all(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+/**
+ * Discard, e.g. remove and destroy a specific filter instance.
+ * If the filter is attached to a connection, it will be removed before
+ * it is destroyed.
+ */
+void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data);
+
+
+ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *buf, size_t len, CURLcode *err);
+ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *err);
+
+#define CURL_CF_SSL_DEFAULT -1
+#define CURL_CF_SSL_DISABLE 0
+#define CURL_CF_SSL_ENABLE 1
+
+/**
+ * Setup the filter chain at `sockindex` in connection `conn`, invoking
+ * the instance `setup(remotehost)` methods. If no filter chain is
+ * installed yet, inspects the configuration in `data` to install a
+ * suitable filter chain.
+ */
+CURLcode Curl_conn_setup(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ const struct Curl_dns_entry *remotehost,
+ int ssl_mode);
+
+/**
+ * Bring the filter chain at `sockindex` for connection `data->conn` into
+ * connected state. Which will set `*done` to TRUE.
+ * This can be called on an already connected chain with no side effects.
+ * When not `blocking`, calls may return without error and `*done != TRUE`,
+ * while the individual filters negotiated the connection.
+ */
+CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
+ bool blocking, bool *done);
+
+/**
+ * Check if the filter chain at `sockindex` for connection `conn` is
+ * completely connected.
+ */
+bool Curl_conn_is_connected(struct connectdata *conn, int sockindex);
+
+/**
+ * Determine if we have reached the remote host on IP level, e.g.
+ * have a TCP connection. This turns TRUE before a possible SSL
+ * handshake has been started/done.
+ */
+bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
+
+/**
+ * Determine if the connection is using SSL to the remote host
+ * (or will be once connected). This will return FALSE, if SSL
+ * is only used in proxying and not for the tunnel itself.
+ */
+bool Curl_conn_is_ssl(struct Curl_easy *data, int sockindex);
+
+/**
+ * Close the filter chain at `sockindex` for connection `data->conn`.
+ * Filters remain in place and may be connected again afterwards.
+ */
+void Curl_conn_close(struct Curl_easy *data, int sockindex);
+
+/**
+ * Return if data is pending in some connection filter at chain
+ * `sockindex` for connection `data->conn`.
+ */
+bool Curl_conn_data_pending(struct Curl_easy *data,
+ int sockindex);
+
+/**
+ * Get any select fd flags and the socket filters at chain `sockindex`
+ * at connection `conn` might be waiting for.
+ */
+int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
+ curl_socket_t *socks);
+
+/**
+ * Receive data through the filter chain at `sockindex` for connection
+ * `data->conn`. Copy at most `len` bytes into `buf`. Return the
+ * actuel number of bytes copied or a negative value on error.
+ * The error code is placed into `*code`.
+ */
+ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf,
+ size_t len, CURLcode *code);
+
+/**
+ * Send `len` bytes of data from `buf` through the filter chain `sockindex`
+ * at connection `data->conn`. Return the actual number of bytes written
+ * or a negative value on error.
+ * The error code is placed into `*code`.
+ */
+ssize_t Curl_conn_send(struct Curl_easy *data, int sockindex,
+ const void *buf, size_t len, CURLcode *code);
+
+/**
+ * The easy handle `data` is being attached (served) by connection `conn`.
+ * All filters are informed to adapt to handling `data`.
+ * Note: there may be several `data` attached to a connection at the same
+ * time.
+ */
+void Curl_conn_attach_data(struct connectdata *conn,
+ struct Curl_easy *data);
+
+/**
+ * The easy handle `data` is being detached (no longer served)
+ * by connection `conn`. All filters are informed to release any resources
+ * related to `data`.
+ * Note: there may be several `data` attached to a connection at the same
+ * time.
+ */
+void Curl_conn_detach_data(struct connectdata *conn,
+ struct Curl_easy *data);
+
+void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
+ const char **phost, const char **pdisplay_host,
+ int *pport);
+
+
+#endif /* HEADER_CURL_CFILTERS_H */
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index ac007c6..af04138 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -48,13 +48,6 @@
#include <arpa/inet.h>
#endif
-#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
-#include <sys/filio.h>
-#endif
-#ifdef NETWARE
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
#ifdef __VMS
#include <in.h>
#include <inet.h>
@@ -64,6 +57,7 @@
#include "sendf.h"
#include "if2ip.h"
#include "strerror.h"
+#include "cfilters.h"
#include "connect.h"
#include "select.h"
#include "url.h" /* for Curl_safefree() */
@@ -79,7 +73,6 @@
#include "share.h"
#include "version_win32.h"
#include "quic.h"
-#include "socks.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -237,10 +230,9 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
return timeout_ms;
}
-static CURLcode bindlocal(struct Curl_easy *data,
+static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t sockfd, int af, unsigned int scope)
{
- struct connectdata *conn = data->conn;
struct Curl_sockaddr_storage sa;
struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
@@ -398,18 +390,23 @@ static CURLcode bindlocal(struct Curl_easy *data,
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
char *scope_ptr = strchr(myhost, '%');
if(scope_ptr)
- *(scope_ptr++) = 0;
+ *(scope_ptr++) = '\0';
#endif
if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
si6->sin6_family = AF_INET6;
si6->sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
- if(scope_ptr)
+ if(scope_ptr) {
/* The "myhost" string either comes from Curl_if2ip or from
Curl_printable_address. The latter returns only numeric scope
IDs and the former returns none at all. So the scope ID, if
present, is known to be numeric */
- si6->sin6_scope_id = atoi(scope_ptr);
+ unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
+ if(scope_id > UINT_MAX)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+
+ si6->sin6_scope_id = (unsigned int)scope_id;
+ }
#endif
}
sizeof_sa = sizeof(struct sockaddr_in6);
@@ -771,123 +768,45 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
Curl_persistconninfo(data, conn, local_ip, local_port);
}
-/* After a TCP connection to the proxy has been verified, this function does
- the next magic steps. If 'done' isn't set TRUE, it is not done yet and
- must be called again.
-
- Note: this function's sub-functions call failf()
-
-*/
-static CURLcode connect_SOCKS(struct Curl_easy *data, int sockindex,
- bool *done)
-{
- CURLcode result = CURLE_OK;
-#ifndef CURL_DISABLE_PROXY
- CURLproxycode pxresult = CURLPX_OK;
- struct connectdata *conn = data->conn;
- if(conn->bits.socksproxy) {
- /* for the secondary socket (FTP), use the "connect to host"
- * but ignore the "connect to port" (use the secondary port)
- */
- const char * const host =
- conn->bits.httpproxy ?
- conn->http_proxy.host.name :
- conn->bits.conn_to_host ?
- conn->conn_to_host.name :
- sockindex == SECONDARYSOCKET ?
- conn->secondaryhostname : conn->host.name;
- const int port =
- conn->bits.httpproxy ? (int)conn->http_proxy.port :
- sockindex == SECONDARYSOCKET ? conn->secondary_port :
- conn->bits.conn_to_port ? conn->conn_to_port :
- conn->remote_port;
- switch(conn->socks_proxy.proxytype) {
- case CURLPROXY_SOCKS5:
- case CURLPROXY_SOCKS5_HOSTNAME:
- pxresult = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
- host, port, sockindex, data, done);
- break;
-
- case CURLPROXY_SOCKS4:
- case CURLPROXY_SOCKS4A:
- pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
- data, done);
- break;
-
- default:
- failf(data, "unknown proxytype option given");
- result = CURLE_COULDNT_CONNECT;
- } /* switch proxytype */
- if(pxresult) {
- result = CURLE_PROXY;
- data->info.pxcode = pxresult;
- }
- }
- else
-#else
- (void)data;
- (void)sockindex;
-#endif /* CURL_DISABLE_PROXY */
- *done = TRUE; /* no SOCKS proxy, so consider us connected */
-
- return result;
-}
-
/*
- * post_SOCKS() is called after a successful connect to the peer, which
- * *could* be a SOCKS proxy
+ * post_connect() is called after a successful connect to the peer
*/
-static void post_SOCKS(struct Curl_easy *data,
+static void post_connect(struct Curl_easy *data,
struct connectdata *conn,
- int sockindex,
- bool *connected)
+ int sockindex)
{
- conn->bits.tcpconnect[sockindex] = TRUE;
-
- *connected = TRUE;
- if(sockindex == FIRSTSOCKET)
- Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
Curl_updateconninfo(data, conn, conn->sock[sockindex]);
Curl_verboseconnect(data, conn);
data->info.numconnects++; /* to track the number of connections made */
}
/*
- * Curl_is_connected() checks if the socket has connected.
+ * is_connected() checks if the socket has connected.
*/
-
-CURLcode Curl_is_connected(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- bool *connected)
+static CURLcode is_connected(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ bool *connected)
{
CURLcode result = CURLE_OK;
timediff_t allow;
int error = 0;
struct curltime now;
int rc = 0;
- unsigned int i;
+ int i;
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
*connected = FALSE; /* a very negative world view is best */
- if(conn->bits.tcpconnect[sockindex]) {
- /* we are connected already! */
- *connected = TRUE;
- return CURLE_OK;
- }
-
now = Curl_now();
- if(SOCKS_STATE(conn->cnnct.state)) {
- /* still doing SOCKS */
- result = connect_SOCKS(data, sockindex, connected);
- if(!result && *connected)
- post_SOCKS(data, conn, sockindex, connected);
- return result;
- }
-
+ /* Check if any of the conn->tempsock we use for establishing connections
+ * succeeded and, if so, close any ongoing other ones.
+ * Transfer the successful conn->tempsock to conn->sock[sockindex]
+ * and set conn->tempsock to CURL_SOCKET_BAD.
+ * If transport is QUIC, we need to shutdown the ongoing 'other'
+ * connect attempts in a QUIC appropriate way. */
for(i = 0; i<2; i++) {
const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
@@ -901,7 +820,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
conn->sock[sockindex] = conn->tempsock[i];
conn->ip_addr = conn->tempaddr[i];
conn->tempsock[i] = CURL_SOCKET_BAD;
- post_SOCKS(data, conn, sockindex, connected);
+ post_connect(data, conn, sockindex);
connkeep(conn, "HTTP/3 default");
if(conn->tempsock[other] != CURL_SOCKET_BAD)
Curl_quic_disconnect(data, conn, other);
@@ -963,14 +882,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
conn->tempsock[other] = CURL_SOCKET_BAD;
}
- /* see if we need to kick off any SOCKS proxy magic once we
- connected */
- result = connect_SOCKS(data, sockindex, connected);
- if(result || !*connected)
- return result;
-
- post_SOCKS(data, conn, sockindex, connected);
-
+ *connected = TRUE;
return CURLE_OK;
}
}
@@ -1207,7 +1119,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
return result;
/* store remote address and port used in this connection attempt */
- if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen,
+ if(!Curl_addr2string(&addr.sa_addr, addr.addrlen,
ipaddress, &port)) {
/* malformed address or bug in inet_ntop, try next address */
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
@@ -1261,8 +1173,8 @@ static CURLcode singleipconnect(struct Curl_easy *data,
|| addr.family == AF_INET6
#endif
) {
- result = bindlocal(data, sockfd, addr.family,
- Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
+ result = bindlocal(data, conn, sockfd, addr.family,
+ Curl_ipv6_scope(&addr.sa_addr));
if(result) {
Curl_closesocket(data, conn, sockfd); /* close socket and bail out */
if(result == CURLE_UNSUPPORTED_PROTOCOL) {
@@ -1521,12 +1433,13 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
/*
* Check if a connection seems to be alive.
*/
-bool Curl_connalive(struct connectdata *conn)
+bool Curl_connalive(struct Curl_easy *data, struct connectdata *conn)
{
+ (void)data;
/* First determine if ssl */
- if(conn->ssl[FIRSTSOCKET].use) {
+ if(Curl_conn_is_ssl(data, FIRSTSOCKET)) {
/* use the SSL context */
- if(!Curl_ssl_check_cxn(conn))
+ if(!Curl_ssl_check_cxn(data, conn))
return false; /* FIN received */
}
/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
@@ -1714,16 +1627,306 @@ void Curl_conncontrol(struct connectdata *conn,
}
}
-/* Data received can be cached at various levels, so check them all here. */
-bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
+typedef enum {
+ SCFST_INIT,
+ SCFST_WAITING,
+ SCFST_DONE
+} cf_connect_state;
+
+struct socket_cf_ctx {
+ const struct Curl_dns_entry *remotehost;
+ cf_connect_state state;
+};
+
+static int socket_cf_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ struct connectdata *conn = cf->conn;
+ int i, s, rc = GETSOCK_BLANK;
+
+ (void)data;
+ if(cf->connected) {
+ return rc;
+ }
+
+ for(i = s = 0; i<2; i++) {
+ if(conn->tempsock[i] != CURL_SOCKET_BAD) {
+ socks[s] = conn->tempsock[i];
+ rc |= GETSOCK_WRITESOCK(s);
+#ifdef ENABLE_QUIC
+ if(conn->transport == TRNSPRT_QUIC)
+ /* when connecting QUIC, we want to read the socket too */
+ rc |= GETSOCK_READSOCK(s);
+#endif
+ s++;
+ }
+ }
+
+ return rc;
+}
+
+static CURLcode socket_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ struct connectdata *conn = cf->conn;
+ int sockindex = cf->sockindex;
+ struct socket_cf_ctx *ctx = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ (void)blocking;
+ DEBUGASSERT(ctx);
+ *done = FALSE;
+ switch(ctx->state) {
+ case SCFST_INIT:
+ DEBUGASSERT(CURL_SOCKET_BAD == conn->sock[sockindex]);
+ DEBUGASSERT(!cf->connected);
+ result = Curl_connecthost(data, conn, ctx->remotehost);
+ if(!result)
+ ctx->state = SCFST_WAITING;
+ break;
+ case SCFST_WAITING:
+ result = is_connected(data, conn, sockindex, done);
+ if(!result && *done) {
+ Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+ if(Curl_conn_is_ssl(data, FIRSTSOCKET) ||
+ (conn->handler->protocol & PROTO_FAMILY_SSH))
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ post_connect(data, conn, sockindex);
+ ctx->state = SCFST_DONE;
+ cf->connected = TRUE;
+ }
+ break;
+ case SCFST_DONE:
+ *done = TRUE;
+ break;
+ }
+ return result;
+}
+
+static CURLcode socket_cf_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct Curl_dns_entry *remotehost)
+{
+ struct socket_cf_ctx *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx);
+ if(ctx->remotehost != remotehost) {
+ if(ctx->remotehost) {
+ /* switching dns entry? TODO: reset? */
+ }
+ ctx->remotehost = remotehost;
+ }
+ DEBUGF(infof(data, CFMSG(cf, "setup(remotehost=%s)"),
+ cf->conn->hostname_resolve));
+ return CURLE_OK;
+}
+
+static void socket_cf_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ int sockindex = cf->sockindex;
+ struct socket_cf_ctx *ctx = cf->ctx;
+
+ DEBUGASSERT(ctx);
+ /* close possibly still open sockets */
+ if(CURL_SOCKET_BAD != cf->conn->sock[sockindex]) {
+ Curl_closesocket(data, cf->conn, cf->conn->sock[sockindex]);
+ cf->conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
+ if(CURL_SOCKET_BAD != cf->conn->tempsock[sockindex]) {
+ Curl_closesocket(data, cf->conn, cf->conn->tempsock[sockindex]);
+ cf->conn->tempsock[sockindex] = CURL_SOCKET_BAD;
+ }
+ cf->connected = FALSE;
+ ctx->state = SCFST_INIT;
+}
+
+static void socket_cf_get_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char **phost,
+ const char **pdisplay_host,
+ int *pport)
+{
+ (void)data;
+ *phost = cf->conn->host.name;
+ *pdisplay_host = cf->conn->host.dispname;
+ *pport = cf->conn->port;
+}
+
+static bool socket_cf_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
int readable;
+ (void)data;
+ DEBUGASSERT(cf);
+
+ readable = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0);
+ return (readable > 0 && (readable & CURL_CSELECT_IN));
+}
+
+static ssize_t socket_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *buf, size_t len, CURLcode *err)
+{
+ ssize_t nwritten;
+ nwritten = Curl_send_plain(data, cf->sockindex, buf, len, err);
+ return nwritten;
+}
+
+static ssize_t socket_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *err)
+{
+ ssize_t nread;
+ nread = Curl_recv_plain(data, cf->sockindex, buf, len, err);
+ return nread;
+}
+
+static void socket_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct socket_cf_ctx *state = cf->ctx;
+
+ (void)data;
+ if(cf->connected) {
+ socket_cf_close(cf, data);
+ }
+ /* release any resources held in state */
+ Curl_safefree(state);
+}
+
+static const struct Curl_cftype cft_socket = {
+ "SOCKET",
+ CF_TYPE_IP_CONNECT,
+ socket_cf_destroy,
+ socket_cf_setup,
+ socket_cf_connect,
+ socket_cf_close,
+ socket_cf_get_host,
+ socket_cf_get_select_socks,
+ socket_cf_data_pending,
+ socket_cf_send,
+ socket_cf_recv,
+ Curl_cf_def_attach_data,
+ Curl_cf_def_detach_data,
+};
+
+CURLcode Curl_conn_socket_set(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result;
+ struct Curl_cfilter *cf = NULL;
+ struct socket_cf_ctx *scf_ctx = NULL;
+
+ /* Need to be first */
DEBUGASSERT(conn);
+ DEBUGASSERT(!conn->cfilter[sockindex]);
+ scf_ctx = calloc(sizeof(*scf_ctx), 1);
+ if(!scf_ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ result = Curl_cf_create(&cf, &cft_socket, scf_ctx);
+ if(result)
+ goto out;
+ Curl_conn_cf_add(data, conn, sockindex, cf);
- if(Curl_ssl_data_pending(conn, sockindex) ||
- Curl_recv_has_postponed_data(conn, sockindex))
- return true;
+out:
+ if(result) {
+ Curl_safefree(cf);
+ Curl_safefree(scf_ctx);
+ }
+ return result;
+}
- readable = SOCKET_READABLE(conn->sock[sockindex], 0);
- return (readable > 0 && (readable & CURL_CSELECT_IN));
+static CURLcode socket_accept_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ /* we start accepted, if we ever close, we cannot go on */
+ (void)data;
+ (void)blocking;
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ return CURLE_FAILED_INIT;
+}
+
+static CURLcode socket_accept_cf_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct Curl_dns_entry *remotehost)
+{
+ /* we start accepted, if we ever close, we cannot go on */
+ (void)data;
+ (void)remotehost;
+ if(cf->connected) {
+ return CURLE_OK;
+ }
+ return CURLE_FAILED_INIT;
+}
+
+static const struct Curl_cftype cft_socket_accept = {
+ "SOCKET-ACCEPT",
+ CF_TYPE_IP_CONNECT,
+ socket_cf_destroy,
+ socket_accept_cf_setup,
+ socket_accept_cf_connect,
+ socket_cf_close,
+ socket_cf_get_host, /* TODO: not accurate */
+ Curl_cf_def_get_select_socks,
+ socket_cf_data_pending,
+ socket_cf_send,
+ socket_cf_recv,
+ Curl_cf_def_attach_data,
+ Curl_cf_def_detach_data,
+};
+
+CURLcode Curl_conn_socket_accepted_set(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex, curl_socket_t *s)
+{
+ CURLcode result;
+ struct Curl_cfilter *cf = NULL;
+ struct socket_cf_ctx *scf_ctx = NULL;
+
+ cf = conn->cfilter[sockindex];
+ if(cf && cf->cft == &cft_socket_accept) {
+ /* already an accept filter installed, just replace the socket */
+ scf_ctx = cf->ctx;
+ result = CURLE_OK;
+ }
+ else {
+ /* replace any existing */
+ Curl_conn_cf_discard_all(data, conn, sockindex);
+ scf_ctx = calloc(sizeof(*scf_ctx), 1);
+ if(!scf_ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ result = Curl_cf_create(&cf, &cft_socket_accept, scf_ctx);
+ if(result)
+ goto out;
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+ }
+
+ /* close any existing socket and replace */
+ Curl_closesocket(data, conn, conn->sock[sockindex]);
+ conn->sock[sockindex] = *s;
+ conn->bits.sock_accepted = TRUE;
+ cf->connected = TRUE;
+ scf_ctx->state = SCFST_DONE;
+
+out:
+ if(result) {
+ Curl_safefree(cf);
+ Curl_safefree(scf_ctx);
+ }
+ return result;
}
diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h
index 582ff08..1e90a85 100644
--- a/Utilities/cmcurl/lib/connect.h
+++ b/Utilities/cmcurl/lib/connect.h
@@ -29,11 +29,6 @@
#include "sockaddr.h"
#include "timeval.h"
-CURLcode Curl_is_connected(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- bool *connected);
-
CURLcode Curl_connecthost(struct Curl_easy *data,
struct connectdata *conn,
const struct Curl_dns_entry *host);
@@ -61,7 +56,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
/*
* Check if a connection seems to be alive.
*/
-bool Curl_connalive(struct connectdata *conn);
+bool Curl_connalive(struct Curl_easy *data, struct connectdata *conn);
#ifdef USE_WINSOCK
/* When you run a program that uses the Windows Sockets API, you may
@@ -153,6 +148,13 @@ void Curl_conncontrol(struct connectdata *conn,
#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP)
#endif
-bool Curl_conn_data_pending(struct connectdata *conn, int sockindex);
+CURLcode Curl_conn_socket_set(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+CURLcode Curl_conn_socket_accepted_set(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ curl_socket_t *s);
#endif /* HEADER_CURL_CONNECT_H */
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index 8eaedee..bccf2e8 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -300,12 +300,11 @@ static char *sanitize_cookie_path(const char *cookie_path)
/* some stupid site sends path attribute with '"'. */
len = strlen(new_path);
if(new_path[0] == '\"') {
- memmove((void *)new_path, (const void *)(new_path + 1), len);
+ memmove(new_path, new_path + 1, len);
len--;
}
if(len && (new_path[len - 1] == '\"')) {
- new_path[len - 1] = 0x0;
- len--;
+ new_path[--len] = 0x0;
}
/* RFC6265 5.2.4 The Path Attribute */
@@ -515,7 +514,7 @@ Curl_cookie_add(struct Curl_easy *data,
return NULL; /* bail out if we're this low on memory */
if(httpheader) {
- /* This line was read off a HTTP-header */
+ /* This line was read off an HTTP-header */
char name[MAX_NAME];
char what[MAX_NAME];
const char *ptr;
@@ -605,9 +604,9 @@ Curl_cookie_add(struct Curl_easy *data,
* only test for names where that can possibly be true.
*/
if(nlen > 3 && name[0] == '_' && name[1] == '_') {
- if(!strncmp("__Secure-", name, 9))
+ if(strncasecompare("__Secure-", name, 9))
co->prefix |= COOKIE_PREFIX__SECURE;
- else if(!strncmp("__Host-", name, 7))
+ else if(strncasecompare("__Host-", name, 7))
co->prefix |= COOKIE_PREFIX__HOST;
}
@@ -780,10 +779,16 @@ Curl_cookie_add(struct Curl_easy *data,
offt = curlx_strtoofft((*co->maxage == '\"')?
&co->maxage[1]:&co->maxage[0], NULL, 10,
&co->expires);
- if(offt == CURL_OFFT_FLOW)
+ switch(offt) {
+ case CURL_OFFT_FLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
- else if(!offt) {
+ break;
+ case CURL_OFFT_INVAL:
+ /* negative or otherwise bad, expire */
+ co->expires = 1;
+ break;
+ case CURL_OFFT_OK:
if(!co->expires)
/* already expired */
co->expires = 1;
@@ -792,6 +797,7 @@ Curl_cookie_add(struct Curl_easy *data,
co->expires = CURL_OFF_T_MAX;
else
co->expires += now;
+ break;
}
}
else if(co->expirestr) {
@@ -864,7 +870,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
else {
/*
- * This line is NOT a HTTP header style line, we do offer support for
+ * This line is NOT an HTTP header style line, we do offer support for
* reading the odd netscape cookies-file format here
*/
char *ptr;
@@ -1258,7 +1264,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
fp = NULL;
}
else {
- fp = fopen(file, FOPEN_READTEXT);
+ fp = fopen(file, "rb");
if(!fp)
infof(data, "WARNING: failed to open cookie file \"%s\"", file);
}
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c
index 72e778b..bcea883 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.c
+++ b/Utilities/cmcurl/lib/curl_addrinfo.c
@@ -47,11 +47,6 @@
# include <inet.h>
#endif
-#if defined(NETWARE) && defined(__NOVELL_LIBC__)
-# undef in_addr_t
-# define in_addr_t unsigned long
-#endif
-
#include <stddef.h>
#include "curl_addrinfo.h"
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index b8a58c8..9cde948 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -143,9 +143,6 @@
/* Define to 1 if you have the <arpa/tftp.h> header file. */
#cmakedefine HAVE_ARPA_TFTP_H 1
-/* Define to 1 if you have the <assert.h> header file. */
-#cmakedefine HAVE_ASSERT_H 1
-
/* Define to 1 if you have _Atomic support. */
#cmakedefine HAVE_ATOMIC 1
@@ -167,9 +164,6 @@
/* Define to 1 if you have the `closesocket' function. */
#cmakedefine HAVE_CLOSESOCKET 1
-/* Define to 1 if you have the <errno.h> header file. */
-#cmakedefine HAVE_ERRNO_H 1
-
/* Define to 1 if you have the fcntl function. */
#cmakedefine HAVE_FCNTL 1
@@ -590,9 +584,6 @@
/* Define to 1 if you have the ws2tcpip.h header file. */
#cmakedefine HAVE_WS2TCPIP_H 1
-/* Define if you have the <process.h> header file. */
-#cmakedefine HAVE_PROCESS_H 1
-
/* Define to 1 if you need the lber.h header file even with ldap.h */
#cmakedefine NEED_LBER_H 1
@@ -806,8 +797,5 @@ ${SIZEOF_TIME_T_CODE}
/* to enable Windows IDN */
#cmakedefine USE_WIN32_IDN 1
-/* to make the compiler know the prototypes of Windows IDN APIs */
-#cmakedefine WANT_IDN_PROTOTYPES 1
-
/* Define to 1 to enable websocket support. */
#cmakedefine USE_WEBSOCKETS 1
diff --git a/Utilities/cmcurl/lib/curl_endian.h b/Utilities/cmcurl/lib/curl_endian.h
index 758d55f..08d52e7 100644
--- a/Utilities/cmcurl/lib/curl_endian.h
+++ b/Utilities/cmcurl/lib/curl_endian.h
@@ -33,13 +33,4 @@ unsigned int Curl_read32_le(const unsigned char *buf);
/* Converts a 16-bit integer from big endian */
unsigned short Curl_read16_be(const unsigned char *buf);
-#if (SIZEOF_CURL_OFF_T > 4)
-/* Converts a 64-bit integer to little endian */
-#if defined(HAVE_LONGLONG)
-void Curl_write64_le(const long long value, unsigned char *buffer);
-#else
-void Curl_write64_le(const __int64 value, unsigned char *buffer);
-#endif
-#endif
-
#endif /* HEADER_CURL_ENDIAN_H */
diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c
index 0dd1eb5..b8a85a9 100644
--- a/Utilities/cmcurl/lib/curl_fnmatch.c
+++ b/Utilities/cmcurl/lib/curl_fnmatch.c
@@ -76,9 +76,9 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
parsekey_state state = CURLFNM_PKW_INIT;
#define KEYLEN 10
char keyword[KEYLEN] = { 0 };
- int found = FALSE;
int i;
unsigned char *p = *pattern;
+ bool found = FALSE;
for(i = 0; !found; i++) {
char c = *p++;
if(i >= KEYLEN)
@@ -368,14 +368,13 @@ int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
*/
int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
{
- int rc;
(void)ptr; /* the argument is specified by the curl_fnmatch_callback
prototype, but not used by Curl_fnmatch() */
if(!pattern || !string) {
return CURL_FNMATCH_FAIL;
}
- rc = fnmatch(pattern, string, 0);
- switch(rc) {
+
+ switch(fnmatch(pattern, string, 0)) {
case 0:
return CURL_FNMATCH_MATCH;
case FNM_NOMATCH:
diff --git a/Utilities/cmcurl/lib/curl_get_line.c b/Utilities/cmcurl/lib/curl_get_line.c
index 22e3705..0d8c285 100644
--- a/Utilities/cmcurl/lib/curl_get_line.c
+++ b/Utilities/cmcurl/lib/curl_get_line.c
@@ -41,17 +41,41 @@ char *Curl_get_line(char *buf, int len, FILE *input)
bool partial = FALSE;
while(1) {
char *b = fgets(buf, len, input);
+
if(b) {
size_t rlen = strlen(b);
- if(rlen && (b[rlen-1] == '\n')) {
+
+ if(!rlen)
+ break;
+
+ if(b[rlen-1] == '\n') {
+ /* b is \n terminated */
if(partial) {
partial = FALSE;
continue;
}
return b;
}
- /* read a partial, discard the next piece that ends with newline */
- partial = TRUE;
+ else if(feof(input)) {
+ if(partial)
+ /* Line is already too large to return, ignore rest */
+ break;
+
+ if(rlen + 1 < (size_t) len) {
+ /* b is EOF terminated, insert missing \n */
+ b[rlen] = '\n';
+ b[rlen + 1] = '\0';
+ return b;
+ }
+ else
+ /* Maximum buffersize reached + EOF
+ * This line is impossible to add a \n to so we'll ignore it
+ */
+ break;
+ }
+ else
+ /* Maximum buffersize reached */
+ partial = TRUE;
}
else
break;
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index 38e193c..690f8f7 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -186,9 +186,9 @@ static void setup_des_key(const unsigned char *key_56,
#elif defined(USE_NSS)
/*
- * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using
- * the expanded key. The caller is responsible for giving 64 bit of valid
- * data is IN and (at least) 64 bit large buffer as OUT.
+ * encrypt_des() expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of
+ * data, using the expanded key. IN should point to 64 bits of source data,
+ * OUT to a 64 bit output buffer.
*/
static bool encrypt_des(const unsigned char *in, unsigned char *out,
const unsigned char *key_56)
@@ -658,7 +658,8 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime));
memcpy(ptr + 32, challenge_client, 8);
- memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
+ if(ntlm->target_info_len)
+ memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
/* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
memcpy(ptr + 8, &ntlm->nonce[0], 8);
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c
index 33dcf0c..fcf5075 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_wb.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c
@@ -385,7 +385,7 @@ CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
bool proxy)
{
/* point to the address of the pointer that holds the string to send to the
- server, which is for a plain host or for a HTTP proxy */
+ server, which is for a plain host or for an HTTP proxy */
char **allocuserpwd;
/* point to the name and password for this */
const char *userp;
diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c
index b55e830..f00e3ee 100644
--- a/Utilities/cmcurl/lib/curl_path.c
+++ b/Utilities/cmcurl/lib/curl_path.c
@@ -71,10 +71,14 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
/* It is referenced to the home directory, so strip the
leading '/' */
memcpy(real_path, homedir, homelen);
- real_path[homelen] = '/';
- real_path[homelen + 1] = '\0';
+ /* Only add a trailing '/' if homedir does not end with one */
+ if(homelen == 0 || real_path[homelen - 1] != '/') {
+ real_path[homelen] = '/';
+ homelen++;
+ real_path[homelen] = '\0';
+ }
if(working_path_len > 3) {
- memcpy(real_path + homelen + 1, working_path + 3,
+ memcpy(real_path + homelen, working_path + 3,
1 + working_path_len -3);
}
}
@@ -148,15 +152,12 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
break;
}
if(cp[i] == '\0') { /* End of string */
- /*error("Unterminated quote");*/
goto fail;
}
if(cp[i] == '\\') { /* Escaped characters */
i++;
if(cp[i] != '\'' && cp[i] != '\"' &&
cp[i] != '\\') {
- /*error("Bad escaped character '\\%c'",
- cp[i]);*/
goto fail;
}
}
@@ -164,7 +165,6 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
}
if(j == 0) {
- /*error("Empty quotes");*/
goto fail;
}
*cpp = cp + i + strspn(cp + i, WHITESPACE);
diff --git a/Utilities/cmcurl/lib/curl_range.c b/Utilities/cmcurl/lib/curl_range.c
index dd92d05..4999936 100644
--- a/Utilities/cmcurl/lib/curl_range.c
+++ b/Utilities/cmcurl/lib/curl_range.c
@@ -44,12 +44,12 @@ CURLcode Curl_range(struct Curl_easy *data)
if(data->state.use_range && data->state.range) {
CURLofft from_t;
CURLofft to_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+ from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
if(from_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+ to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
if(to_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
if((to_t == CURL_OFFT_INVAL) && !from_t) {
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index b0c3710..1932cb4 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -85,7 +85,7 @@ const struct Curl_handler Curl_handler_rtmp = {
PORT_RTMP, /* defport */
CURLPROTO_RTMP, /* protocol */
CURLPROTO_RTMP, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
const struct Curl_handler Curl_handler_rtmpt = {
@@ -108,7 +108,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
PORT_RTMPT, /* defport */
CURLPROTO_RTMPT, /* protocol */
CURLPROTO_RTMPT, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
const struct Curl_handler Curl_handler_rtmpe = {
@@ -131,7 +131,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
PORT_RTMP, /* defport */
CURLPROTO_RTMPE, /* protocol */
CURLPROTO_RTMPE, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
const struct Curl_handler Curl_handler_rtmpte = {
@@ -154,7 +154,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
PORT_RTMPT, /* defport */
CURLPROTO_RTMPTE, /* protocol */
CURLPROTO_RTMPTE, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
const struct Curl_handler Curl_handler_rtmps = {
@@ -177,7 +177,7 @@ const struct Curl_handler Curl_handler_rtmps = {
PORT_RTMPS, /* defport */
CURLPROTO_RTMPS, /* protocol */
CURLPROTO_RTMP, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
const struct Curl_handler Curl_handler_rtmpts = {
@@ -200,7 +200,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
PORT_RTMPS, /* defport */
CURLPROTO_RTMPTS, /* protocol */
CURLPROTO_RTMPT, /* family */
- PROTOPT_NONE /* flags*/
+ PROTOPT_NONE /* flags */
};
static CURLcode rtmp_setup_connection(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 9684ee4..46ee800 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -44,6 +44,7 @@
#include "curl_base64.h"
#include "curl_md5.h"
#include "vauth/vauth.h"
+#include "cfilters.h"
#include "vtls/vtls.h"
#include "curl_hmac.h"
#include "curl_sasl.h"
@@ -340,8 +341,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
struct bufref resp;
saslstate state1 = SASL_STOP;
saslstate state2 = SASL_FINAL;
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
+ const char *hostname, *disp_hostname;
+ int port;
#if defined(USE_KERBEROS5) || defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
@@ -350,6 +351,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref nullmsg;
+ Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
Curl_bufref_init(&nullmsg);
Curl_bufref_init(&resp);
sasl->force_ir = force_ir; /* Latch for future use */
@@ -525,8 +527,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn = data->conn;
saslstate newstate = SASL_FINAL;
struct bufref resp;
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
+ const char *hostname, *disp_hostname;
+ int port;
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
@@ -536,6 +538,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref serverdata;
+ Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
Curl_bufref_init(&serverdata);
Curl_bufref_init(&resp);
*progress = SASL_INPROGRESS;
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index c3ad25f..084d19a 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -92,7 +92,7 @@
# endif
#endif
-#if defined(macintosh) && defined(__MRC__)
+#ifdef macintosh
# include "config-mac.h"
#endif
@@ -112,6 +112,10 @@
# include "config-plan9.h"
#endif
+#ifdef MSDOS
+# include "config-dos.h"
+#endif
+
#endif /* HAVE_CONFIG_H */
#if defined(_MSC_VER)
@@ -322,9 +326,7 @@
#endif
#include <stdio.h>
-#ifdef HAVE_ASSERT_H
#include <assert.h>
-#endif
#ifdef __TANDEM /* for ns*-tandem-nsk systems */
# if ! defined __LP64
@@ -708,7 +710,7 @@
# define UNUSED_PARAM __attribute__((__unused__))
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
-# define UNUSED_PARAM /*NOTHING*/
+# define UNUSED_PARAM /* NOTHING */
# define WARN_UNUSED_RESULT
#endif
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
index f09b00f..ac4a7f1 100644
--- a/Utilities/cmcurl/lib/curl_setup_once.h
+++ b/Utilities/cmcurl/lib/curl_setup_once.h
@@ -34,10 +34,7 @@
#include <string.h>
#include <stdarg.h>
#include <time.h>
-
-#ifdef HAVE_ERRNO_H
#include <errno.h>
-#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -287,7 +284,7 @@ typedef unsigned int bit;
*/
#undef DEBUGASSERT
-#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
+#if defined(DEBUGBUILD)
#define DEBUGASSERT(x) assert(x)
#else
#define DEBUGASSERT(x) do { } while(0)
diff --git a/Utilities/cmcurl/lib/curl_sha256.h b/Utilities/cmcurl/lib/curl_sha256.h
index 754c761..39523af 100644
--- a/Utilities/cmcurl/lib/curl_sha256.h
+++ b/Utilities/cmcurl/lib/curl_sha256.h
@@ -33,7 +33,7 @@ extern const struct HMAC_params Curl_HMAC_SHA256[1];
#ifdef USE_WOLFSSL
/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
- * sha.h*/
+ * sha.h */
#include <wolfssl/options.h>
#include <wolfssl/openssl/sha.h>
#else
diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c
index eb8e136..dff6167 100644
--- a/Utilities/cmcurl/lib/curl_threads.c
+++ b/Utilities/cmcurl/lib/curl_threads.c
@@ -31,9 +31,7 @@
# include <pthread.h>
# endif
#elif defined(USE_THREADS_WIN32)
-# ifdef HAVE_PROCESS_H
-# include <process.h>
-# endif
+# include <process.h>
#endif
#include "curl_threads.h"
diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c
index 6f7678f..993373e 100644
--- a/Utilities/cmcurl/lib/dict.c
+++ b/Utilities/cmcurl/lib/dict.c
@@ -319,4 +319,4 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
return CURLE_OK;
}
-#endif /*CURL_DISABLE_DICT*/
+#endif /* CURL_DISABLE_DICT */
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index b8ac1ef..d7f93be 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -71,7 +71,6 @@
#include "mime.h"
#include "amigaos.h"
#include "warnless.h"
-#include "multiif.h"
#include "sigpipe.h"
#include "vssh/ssh.h"
#include "setopt.h"
@@ -829,7 +828,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
/* Copy src->set into dst->set first, then deal with the strings
afterwards */
dst->set = src->set;
- Curl_mime_initpart(&dst->set.mimepost, dst);
+ Curl_mime_initpart(&dst->set.mimepost);
/* clear all string pointers first */
memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
@@ -863,7 +862,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
}
/* Duplicate mime data. */
- result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
+ result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
if(src->set.resolve)
dst->state.resolve = dst->set.resolve;
diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c
index e59b63a..03b814e 100644
--- a/Utilities/cmcurl/lib/easyoptions.c
+++ b/Utilities/cmcurl/lib/easyoptions.c
@@ -42,6 +42,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
{"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0},
{"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
+ {"CA_CACHE_TIMEOUT", CURLOPT_CA_CACHE_TIMEOUT, CURLOT_LONG, 0},
{"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
{"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
{"CHUNK_DATA", CURLOPT_CHUNK_DATA, CURLOT_CBPTR, 0},
@@ -241,6 +242,7 @@ struct curl_easyoption Curl_easyopts[] = {
CURLOT_STRING, 0},
{"PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE, CURLOT_LONG, 0},
{"PUT", CURLOPT_PUT, CURLOT_LONG, 0},
+ {"QUICK_EXIT", CURLOPT_QUICK_EXIT, CURLOT_LONG, 0},
{"QUOTE", CURLOPT_QUOTE, CURLOT_SLIST, 0},
{"RANDOM_FILE", CURLOPT_RANDOM_FILE, CURLOT_STRING, 0},
{"RANGE", CURLOPT_RANGE, CURLOT_STRING, 0},
@@ -368,6 +370,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (320 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (322 + 1));
}
#endif
diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c
index da7e552..ed59838 100644
--- a/Utilities/cmcurl/lib/escape.c
+++ b/Utilities/cmcurl/lib/escape.c
@@ -202,7 +202,7 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string,
char *str = NULL;
(void)data;
if(length >= 0) {
- size_t inputlen = length;
+ size_t inputlen = (size_t)length;
size_t outputlen;
CURLcode res = Curl_urldecode(string, inputlen, &str, &outputlen,
REJECT_NADA);
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
index d82d57b..3f642be 100644
--- a/Utilities/cmcurl/lib/file.c
+++ b/Utilities/cmcurl/lib/file.c
@@ -150,9 +150,19 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
char *actual_path;
#endif
size_t real_path_len;
+ CURLcode result;
+
+ if(file->path) {
+ /* already connected.
+ * the handler->connect_it() is normally only called once, but
+ * FILE does a special check on setting up the connection which
+ * calls this explicitly. */
+ *done = TRUE;
+ return CURLE_OK;
+ }
- CURLcode result = Curl_urldecode(data->state.up.path, 0, &real_path,
- &real_path_len, REJECT_ZERO);
+ result = Curl_urldecode(data->state.up.path, 0, &real_path,
+ &real_path_len, REJECT_ZERO);
if(result)
return result;
@@ -226,6 +236,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
file->path = real_path;
#endif
#endif
+ Curl_safefree(file->freepath);
file->freepath = real_path; /* free this when done */
file->fd = fd;
@@ -329,7 +340,7 @@ static CURLcode file_upload(struct Curl_easy *data)
while(!result) {
size_t nread;
- size_t nwrite;
+ ssize_t nwrite;
size_t readcount;
result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount);
if(result)
@@ -340,7 +351,7 @@ static CURLcode file_upload(struct Curl_easy *data)
nread = readcount;
- /*skip bytes before resume point*/
+ /* skip bytes before resume point */
if(data->state.resume_from) {
if((curl_off_t)nread <= data->state.resume_from) {
data->state.resume_from -= nread;
@@ -358,7 +369,7 @@ static CURLcode file_upload(struct Curl_easy *data)
/* write the data to the target */
nwrite = write(fd, buf2, nread);
- if(nwrite != nread) {
+ if((size_t)nwrite != nread) {
result = CURLE_SEND_ERROR;
break;
}
@@ -471,13 +482,13 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
tm->tm_hour,
tm->tm_min,
tm->tm_sec,
- data->set.opt_no_body ? "": "\r\n");
+ data->req.no_body ? "": "\r\n");
result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
if(result)
return result;
/* set the file size to make it available post transfer */
Curl_pgrsSetDownloadSize(data, expected_size);
- if(data->set.opt_no_body)
+ if(data->req.no_body)
return result;
}
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index 46542b4..b30e8de 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -59,7 +59,7 @@
*
* AddHttpPost()
*
- * Adds a HttpPost structure to the list, if parent_post is given becomes
+ * Adds an HttpPost structure to the list, if parent_post is given becomes
* a subpost of parent_post instead of a direct list element.
*
* Returns newly allocated HttpPost on success and NULL if malloc failed.
@@ -135,15 +135,13 @@ static struct FormInfo *AddFormInfo(char *value,
{
struct FormInfo *form_info;
form_info = calloc(1, sizeof(struct FormInfo));
- if(form_info) {
- if(value)
- form_info->value = value;
- if(contenttype)
- form_info->contenttype = contenttype;
- form_info->flags = HTTPPOST_FILENAME;
- }
- else
+ if(!form_info)
return NULL;
+ if(value)
+ form_info->value = value;
+ if(contenttype)
+ form_info->contenttype = contenttype;
+ form_info->flags = HTTPPOST_FILENAME;
if(parent_form_info) {
/* now, point our 'more' to the original 'more' */
@@ -199,7 +197,7 @@ static struct FormInfo *AddFormInfo(char *value,
* CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
* CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
* CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
- * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if an HttpPost struct cannot be allocated
* CURL_FORMADD_MEMORY if some allocation for string copying failed.
* CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
*
@@ -717,10 +715,10 @@ int curl_formget(struct curl_httppost *form, void *arg,
CURLcode result;
curl_mimepart toppart;
- Curl_mime_initpart(&toppart, NULL); /* default form is empty */
+ Curl_mime_initpart(&toppart); /* default form is empty */
result = Curl_getformdata(NULL, &toppart, form, NULL);
if(!result)
- result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
+ result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
NULL, MIMESTRATEGY_FORM);
while(!result) {
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index d02ab99..874725b 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -43,11 +43,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -65,6 +60,7 @@
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "strerror.h"
#include "inet_ntop.h"
@@ -74,7 +70,6 @@
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "multiif.h"
#include "url.h"
-#include "strcase.h"
#include "speedcheck.h"
#include "warnless.h"
#include "http_proxy.h"
@@ -219,14 +214,8 @@ const struct Curl_handler Curl_handler_ftps = {
static void close_secondarysocket(struct Curl_easy *data,
struct connectdata *conn)
{
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
- Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- }
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-#ifndef CURL_DISABLE_PROXY
- conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE;
-#endif
+ Curl_conn_close(data, SECONDARYSOCKET);
+ Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
}
/*
@@ -278,13 +267,13 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
struct sockaddr_in add;
#endif
curl_socklen_t size = (curl_socklen_t) sizeof(add);
+ CURLcode result;
if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
size = sizeof(add);
s = accept(sock, (struct sockaddr *) &add, &size);
}
- Curl_closesocket(data, conn, sock); /* close the first socket */
if(CURL_SOCKET_BAD == s) {
failf(data, "Error accept()ing server connect");
@@ -295,9 +284,11 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
not needing DO_MORE anymore */
conn->bits.do_more = FALSE;
- conn->sock[SECONDARYSOCKET] = s;
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
- conn->bits.sock_accepted = TRUE;
+ /* Replace any filter on SECONDARY with one listeing on this socket */
+ result = Curl_conn_socket_accepted_set(data, conn, SECONDARYSOCKET, &s);
+ if(result)
+ return result;
if(data->set.fsockopt) {
int error = 0;
@@ -441,15 +432,12 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
+ bool connected;
- if(conn->bits.ftp_use_data_ssl) {
- /* since we only have a plaintext TCP connection here, we must now
- * do the TLS stuff */
- infof(data, "Doing the SSL/TLS handshake on the data stream");
- result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
- if(result)
- return result;
- }
+ DEBUGF(infof(data, "ftp InitiateTransfer()"));
+ result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
+ if(result || !connected)
+ return result;
if(conn->proto.ftpc.state_saved == FTP_STOR) {
/* When we know we're uploading a specified file, we can get the file
@@ -497,22 +485,23 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
if(timeout_ms < 0) {
/* if a timeout was already reached, bail out */
failf(data, "Accept timeout occurred while waiting server connect");
- return CURLE_FTP_ACCEPT_TIMEOUT;
+ result = CURLE_FTP_ACCEPT_TIMEOUT;
+ goto out;
}
/* see if the connection request is already here */
result = ReceivedServerConnect(data, connected);
if(result)
- return result;
+ goto out;
if(*connected) {
result = AcceptServerConnect(data);
if(result)
- return result;
+ goto out;
result = InitiateTransfer(data);
if(result)
- return result;
+ goto out;
}
else {
/* Add timeout to multi handle and break out of the loop */
@@ -521,6 +510,8 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
EXPIRE_FTP_ACCEPT);
}
+out:
+ DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result));
return result;
}
@@ -672,7 +663,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
* wait for more data anyway.
*/
}
- else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
+ else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
switch(SOCKET_READABLE(sockfd, interval_ms)) {
case -1: /* select() error, stop reading */
failf(data, "FTP response aborted due to select/poll error: %d",
@@ -821,8 +812,10 @@ static int ftp_domore_getsock(struct Curl_easy *data,
* handle ordinary commands.
*/
- if(SOCKS_STATE(conn->cnnct.state))
- return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET);
+ DEBUGF(infof(data, "ftp_domore_getsock()"));
+ if(conn->cfilter[SECONDARYSOCKET]
+ && !Curl_conn_is_connected(conn, SECONDARYSOCKET))
+ return Curl_conn_get_select_socks(data, SECONDARYSOCKET, socks);
if(FTP_STOP == ftpc->state) {
int bits = GETSOCK_READSOCK(0);
@@ -917,7 +910,7 @@ typedef enum {
static CURLcode ftp_state_use_port(struct Curl_easy *data,
ftpport fcmd) /* start with this */
{
- CURLcode result = CURLE_OK;
+ CURLcode result = CURLE_FTP_PORT_FAILED;
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
curl_socket_t portsock = CURL_SOCKET_BAD;
@@ -966,8 +959,10 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char *port_sep = NULL;
addr = calloc(addrlen + 1, 1);
- if(!addr)
- return CURLE_OUT_OF_MEMORY;
+ if(!addr) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
#ifdef ENABLE_IPV6
if(*string_ftpport == '[') {
@@ -1027,7 +1022,6 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(port_min > port_max)
port_min = port_max = 0;
-
if(*addr != '\0') {
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->ip_addr->ai_family,
@@ -1041,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
host = addr;
break;
case IF2IP_AF_NOT_SUPPORTED:
- return CURLE_FTP_PORT_FAILED;
+ goto out;
case IF2IP_FOUND:
host = hbuf; /* use the hbuf for host name */
}
@@ -1059,8 +1053,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
failf(data, "getsockname() failed: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- free(addr);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
switch(sa->sa_family) {
#ifdef ENABLE_IPV6
@@ -1072,8 +1065,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
break;
}
- if(!r)
- return CURLE_FTP_PORT_FAILED;
+ if(!r) {
+ goto out;
+ }
host = hbuf; /* use this host name */
possibly_non_local = FALSE; /* we know it is local now */
}
@@ -1093,11 +1087,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(!res) {
failf(data, "failed to resolve the address provided to PORT: %s", host);
- free(addr);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
- free(addr);
host = NULL;
/* step 2, create a socket for the requested address */
@@ -1105,8 +1097,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
portsock = CURL_SOCKET_BAD;
error = 0;
for(ai = res; ai; ai = ai->ai_next) {
- result = Curl_socket(data, ai, NULL, &portsock);
- if(result) {
+ if(Curl_socket(data, ai, NULL, &portsock)) {
error = SOCKERRNO;
continue;
}
@@ -1115,8 +1106,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(!ai) {
failf(data, "socket failure: %s",
Curl_strerror(error, buffer, sizeof(buffer)));
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
+ DEBUGF(infof(data, "ftp_state_use_port(), opened socket"));
/* step 3, bind to a suitable local address */
@@ -1145,8 +1137,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
failf(data, "getsockname() failed: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- Curl_closesocket(data, conn, portsock);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
port = port_min;
possibly_non_local = FALSE; /* don't try this again */
@@ -1155,8 +1146,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(error != EADDRINUSE && error != EACCES) {
failf(data, "bind(port=%hu) failed: %s", port,
Curl_strerror(error, buffer, sizeof(buffer)));
- Curl_closesocket(data, conn, portsock);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
}
else
@@ -1165,31 +1155,30 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
port++;
}
- /* maybe all ports were in use already*/
+ /* maybe all ports were in use already */
if(port > port_max) {
failf(data, "bind() failed, we ran out of ports");
- Curl_closesocket(data, conn, portsock);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
/* get the name again after the bind() so that we can extract the
port number it uses now */
sslen = sizeof(ss);
- if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
+ if(getsockname(portsock, sa, &sslen)) {
failf(data, "getsockname() failed: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- Curl_closesocket(data, conn, portsock);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
+ DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port));
/* step 4, listen on the socket */
if(listen(portsock, 1)) {
failf(data, "socket failure: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- Curl_closesocket(data, conn, portsock);
- return CURLE_FTP_PORT_FAILED;
+ goto out;
}
+ DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port));
/* step 5, send the proper FTP command */
@@ -1242,12 +1231,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(result) {
failf(data, "Failure sending EPRT command: %s",
curl_easy_strerror(result));
- Curl_closesocket(data, conn, portsock);
- /* don't retry using PORT */
- ftpc->count1 = PORT;
- /* bail out */
- state(data, FTP_STOP);
- return result;
+ goto out;
}
break;
}
@@ -1273,10 +1257,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(result) {
failf(data, "Failure sending PORT command: %s",
curl_easy_strerror(result));
- Curl_closesocket(data, conn, portsock);
- /* bail out */
- state(data, FTP_STOP);
- return result;
+ goto out;
}
break;
}
@@ -1285,23 +1266,21 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* store which command was sent */
ftpc->count1 = fcmd;
- close_secondarysocket(data, conn);
-
- /* we set the secondary socket variable to this for now, it is only so that
- the cleanup function will close it in case we fail before the true
- secondary stuff is made */
- conn->sock[SECONDARYSOCKET] = portsock;
-
- /* this tcpconnect assignment below is a hackish work-around to make the
- multi interface with active FTP work - as it will not wait for a
- (passive) connect in Curl_is_connected().
-
- The *proper* fix is to make sure that the active connection from the
- server is done in a non-blocking way. Currently, it is still BLOCKING.
- */
- conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
-
+ /* Replace any filter on SECONDARY with one listeing on this socket */
+ result = Curl_conn_socket_accepted_set(data, conn, SECONDARYSOCKET,
+ &portsock);
+ if(result)
+ goto out;
+ portsock = CURL_SOCKET_BAD; /* now held in filter */
state(data, FTP_PORT);
+
+out:
+ if(result) {
+ state(data, FTP_STOP);
+ }
+ if(portsock != CURL_SOCKET_BAD)
+ Curl_closesocket(data, conn, portsock);
+ free(addr);
return result;
}
@@ -1525,7 +1504,7 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
/* If we have selected NOBODY and HEADER, it means that we only want file
information. Which in FTP can't be much more than the file size and
date. */
- if(data->set.opt_no_body && ftpc->file &&
+ if(data->req.no_body && ftpc->file &&
ftp_need_type(conn, data->state.prefer_ascii)) {
/* The SIZE command is _not_ RFC 959 specified, and therefore many servers
may not support it! It is however the only way we have to get a file's
@@ -1804,6 +1783,8 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
infof(data, "Failed EPSV attempt. Disabling EPSV");
/* disable it for next transfer */
conn->bits.ftp_use_epsv = FALSE;
+ Curl_conn_close(data, SECONDARYSOCKET);
+ Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
data->state.errorbuf = FALSE; /* allow error message to get
rewritten */
result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV");
@@ -1951,7 +1932,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
*/
const char * const host_name = conn->bits.socksproxy ?
conn->socks_proxy.host.name : conn->http_proxy.host.name;
- rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr);
+ rc = Curl_resolv(data, host_name, conn->port, FALSE, &addr);
if(rc == CURLRESOLV_PENDING)
/* BLOCKING, ignores the return code but 'addr' will be NULL in
case of failure */
@@ -1993,8 +1974,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
}
}
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
- result = Curl_connecthost(data, conn, addr);
+ result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr,
+ conn->bits.ftp_use_data_ssl?
+ CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
if(result) {
Curl_resolv_unlock(data, addr); /* we're done using this address */
@@ -2092,9 +2074,9 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
#ifdef CURL_FTP_HTTPSTYLE_HEAD
/* If we asked for a time of the file and we actually got one as well,
- we "emulate" a HTTP-style header in our output. */
+ we "emulate" an HTTP-style header in our output. */
- if(data->set.opt_no_body &&
+ if(data->req.no_body &&
ftpc->file &&
data->set.get_filetime &&
(data->info.filetime >= 0) ) {
@@ -2210,6 +2192,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
+ DEBUGF(infof(data, "ftp_state_retr()"));
if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
@@ -2310,7 +2293,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
else
fdigit = start;
/* ignores parsing errors, which will make the size remain unknown */
- (void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
+ (void)curlx_strtoofft(fdigit, NULL, 10, &filesize);
}
else if(ftpcode == 550) { /* "No such file or directory" */
@@ -2465,6 +2448,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if((instate != FTP_LIST) &&
!data->state.prefer_ascii &&
+ !data->set.ignorecl &&
(ftp->downloadsize < 1)) {
/*
* It seems directory listings either don't show the size or very
@@ -2495,7 +2479,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(bytes) {
++bytes;
/* get the number! */
- (void)curlx_strtoofft(bytes, NULL, 0, &size);
+ (void)curlx_strtoofft(bytes, NULL, 10, &size);
}
}
}
@@ -2756,8 +2740,16 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
*/
if((ftpcode == 234) || (ftpcode == 334)) {
- /* Curl_ssl_connect is BLOCKING */
- result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+ /* this was BLOCKING, keep it so for now */
+ bool done;
+ if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
+ result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+ if(result) {
+ /* we failed and bail out */
+ return CURLE_USE_SSL_FAILED;
+ }
+ }
+ result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done);
if(!result) {
conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
@@ -2823,7 +2815,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_CCC:
if(ftpcode < 500) {
/* First shut down the SSL layer (note: this call will block) */
- result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET);
+ result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);
if(result)
failf(data, "Failed to clear the command channel (CCC)");
@@ -3167,7 +3159,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
if(conn->handler->flags & PROTOPT_SSL) {
/* BLOCKING */
- result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+ result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
if(result)
return result;
conn->bits.ftp_use_control_ssl = TRUE;
@@ -3310,14 +3302,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
}
- if(conn->ssl[SECONDARYSOCKET].use) {
- /* The secondary socket is using SSL so we must close down that part
- first before we close the socket for real */
- Curl_ssl_close(data, conn, SECONDARYSOCKET);
-
- /* Note that we keep "use" set to TRUE since that (next) connection is
- still requested to use SSL */
- }
close_secondarysocket(data, conn);
}
@@ -3571,23 +3555,15 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
* complete */
struct FTP *ftp = NULL;
- /* if the second connection isn't done yet, wait for it */
- if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
- if(Curl_connect_ongoing(conn)) {
- /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
- aren't used so we blank their arguments. */
- result = Curl_proxyCONNECT(data, SECONDARYSOCKET, NULL, 0);
-
- return result;
- }
-
- result = Curl_is_connected(data, conn, SECONDARYSOCKET, &connected);
-
- /* Ready to do more? */
- if(connected) {
- DEBUGF(infof(data, "DO-MORE connected phase starts"));
- }
- else {
+ /* if the second connection isn't done yet, wait for it to have
+ * connected to the remote host. When using proxy tunneling, this
+ * means the tunnel needs to have been establish. However, we
+ * can not expect the remote host to talk to us in any way yet.
+ * So, when using ftps: the SSL handshake will not start until we
+ * tell the remote server that we are there. */
+ if(conn->cfilter[SECONDARYSOCKET]) {
+ result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
+ if(result || !Curl_conn_is_ip_connected(data, SECONDARYSOCKET)) {
if(result && (ftpc->count1 == 0)) {
*completep = -1; /* go back to DOING please */
/* this is a EPSV connect failing, try PASV instead */
@@ -3597,19 +3573,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
}
-#ifndef CURL_DISABLE_PROXY
- result = Curl_proxy_connect(data, SECONDARYSOCKET);
- if(result)
- return result;
-
- if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
- return result;
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- return result;
-#endif
-
/* Curl_proxy_connect might have moved the protocol state */
ftp = data->req.p.ftp;
@@ -3739,11 +3702,10 @@ CURLcode ftp_perform(struct Curl_easy *data,
{
/* this is FTP and no proxy */
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
DEBUGF(infof(data, "DO phase starts"));
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* requested no body means no transfer... */
struct FTP *ftp = data->req.p.ftp;
ftp->transfer = PPTRANSFER_INFO;
@@ -3759,7 +3721,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
/* run the state-machine */
result = ftp_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET);
infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
@@ -4169,7 +4131,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
/* get path before last slash, except for / */
size_t dirlen = slashPos - rawPath;
if(dirlen == 0)
- dirlen++;
+ dirlen = 1;
ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs) {
@@ -4196,13 +4158,14 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
/* current position: begin of next path component */
const char *curPos = rawPath;
- int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */
+ /* number of entries allocated for the 'dirs' array */
+ size_t dirAlloc = 0;
const char *str = rawPath;
for(; *str != 0; ++str)
if (*str == '/')
++dirAlloc;
- if(dirAlloc > 0) {
+ if(dirAlloc) {
ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs) {
free(rawPath);
@@ -4232,7 +4195,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
curPos = slashPos + 1;
}
}
- DEBUGASSERT(ftpc->dirdepth <= dirAlloc);
+ DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
fileName = curPos; /* the rest is the file name (or empty) */
}
break;
@@ -4375,6 +4338,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
{
char *type;
struct FTP *ftp;
+ CURLcode result = CURLE_OK;
data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
if(!ftp)
@@ -4416,7 +4380,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ftp->downloadsize = 0;
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
- return CURLE_OK;
+ return result;
}
#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index 40f5f3f..3d529ef 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -205,9 +205,9 @@ CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
#define FTP_LP_MALFORMATED_PERM 0x01000000
-static int ftp_pl_get_permission(const char *str)
+static unsigned int ftp_pl_get_permission(const char *str)
{
- int permissions = 0;
+ unsigned int permissions = 0;
/* USER */
if(str[0] == 'r')
permissions |= 1 << 8;
@@ -334,7 +334,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
struct ftp_parselist_data *parser = ftpwc->parser;
struct fileinfo *infop;
struct curl_fileinfo *finfo;
- unsigned long i = 0;
+ size_t i = 0;
CURLcode result;
size_t retsize = bufflen;
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
index c3556b3..3a24c65 100644
--- a/Utilities/cmcurl/lib/getinfo.c
+++ b/Utilities/cmcurl/lib/getinfo.c
@@ -533,13 +533,7 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
#ifdef USE_SSL
if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
- unsigned int i;
- for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
- if(conn->ssl[i].use) {
- tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
- break;
- }
- }
+ tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
}
#endif
}
diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c
index 01f4bde..6fbb7de 100644
--- a/Utilities/cmcurl/lib/gopher.c
+++ b/Utilities/cmcurl/lib/gopher.c
@@ -30,6 +30,7 @@
#include <curl/curl.h>
#include "transfer.h"
#include "sendf.h"
+#include "cfilters.h"
#include "connect.h"
#include "progress.h"
#include "gopher.h"
@@ -117,7 +118,9 @@ static CURLcode gopher_connect(struct Curl_easy *data, bool *done)
static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- CURLcode result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+ CURLcode result;
+
+ result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
if(result)
connclose(conn, "Failed TLS connection");
*done = TRUE;
@@ -236,4 +239,4 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
return CURLE_OK;
}
-#endif /*CURL_DISABLE_GOPHER*/
+#endif /* CURL_DISABLE_GOPHER */
diff --git a/Utilities/cmcurl/lib/h2h3.c b/Utilities/cmcurl/lib/h2h3.c
index 50254ad..3a9288d 100644
--- a/Utilities/cmcurl/lib/h2h3.c
+++ b/Utilities/cmcurl/lib/h2h3.c
@@ -36,7 +36,7 @@
/*
* Curl_pseudo_headers() creates the array with pseudo headers to be
- * used in a HTTP/2 or HTTP/3 request.
+ * used in an HTTP/2 or HTTP/3 request.
*/
#if defined(USE_NGHTTP2) || defined(ENABLE_QUIC)
diff --git a/Utilities/cmcurl/lib/h2h3.h b/Utilities/cmcurl/lib/h2h3.h
index 84caec5..c35b706 100644
--- a/Utilities/cmcurl/lib/h2h3.h
+++ b/Utilities/cmcurl/lib/h2h3.h
@@ -45,7 +45,7 @@ struct h2h3req {
/*
* Curl_pseudo_headers() creates the array with pseudo headers to be
- * used in a HTTP/2 or HTTP/3 request. Returns an allocated struct.
+ * used in an HTTP/2 or HTTP/3 request. Returns an allocated struct.
* Free it with Curl_pseudo_free().
*/
CURLcode Curl_pseudo_headers(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
index 0bfbe2e..df50d13 100644
--- a/Utilities/cmcurl/lib/hostasyn.c
+++ b/Utilities/cmcurl/lib/hostasyn.c
@@ -43,10 +43,6 @@
#include <inet.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 941ecac..dd427a2 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -48,10 +48,6 @@
#include <signal.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index 9d31707..3b1d814 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -34,11 +34,6 @@
#include <setjmp.h>
#endif
-#ifdef NETWARE
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
/* Allocate enough memory to hold the full name information structs and
* everything. OSF1 is known to require at least 8872 bytes. The buffer
* required for storing all possible aliases and IP numbers is according to
diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c
index 1dd54e8..109bd1e 100644
--- a/Utilities/cmcurl/lib/hostip4.c
+++ b/Utilities/cmcurl/lib/hostip4.c
@@ -43,10 +43,6 @@
#include <inet.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
@@ -125,14 +121,15 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
int port)
{
-#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
+#if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)) && \
+ defined(HAVE_GETHOSTBYNAME_R_3)
int res;
#endif
struct Curl_addrinfo *ai = NULL;
struct hostent *h = NULL;
struct hostent *buf = NULL;
-#if defined(HAVE_GETADDRINFO_THREADSAFE)
+#if defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)
struct addrinfo hints;
char sbuf[12];
char *sbufptr = NULL;
@@ -280,14 +277,16 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
h = NULL; /* set return code to NULL */
free(buf);
}
-#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
+ HAVE_GETHOSTBYNAME_R */
/*
* Here is code for platforms that don't have a thread safe
* getaddrinfo() nor gethostbyname_r() function or for which
* gethostbyname() is the preferred one.
*/
h = gethostbyname((void *)hostname);
-#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
+ HAVE_GETHOSTBYNAME_R */
if(h) {
ai = Curl_he2ai(h, port);
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
index c62c254..af8bc23 100644
--- a/Utilities/cmcurl/lib/hostip6.c
+++ b/Utilities/cmcurl/lib/hostip6.c
@@ -43,10 +43,6 @@
#include <inet.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c
index ee54363..73d1e50 100644
--- a/Utilities/cmcurl/lib/hostsyn.c
+++ b/Utilities/cmcurl/lib/hostsyn.c
@@ -43,10 +43,6 @@
#include <inet.h>
#endif
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
index e3b686e..c449120 100644
--- a/Utilities/cmcurl/lib/hsts.c
+++ b/Utilities/cmcurl/lib/hsts.c
@@ -39,7 +39,6 @@
#include "parsedate.h"
#include "fopen.h"
#include "rename.h"
-#include "strtoofft.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -158,7 +157,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
do {
while(*p && ISBLANK(*p))
p++;
- if(Curl_strncasecompare("max-age=", p, 8)) {
+ if(strncasecompare("max-age=", p, 8)) {
bool quoted = FALSE;
CURLofft offt;
char *endp;
@@ -187,7 +186,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
}
gotma = TRUE;
}
- else if(Curl_strncasecompare("includesubdomains", p, 17)) {
+ else if(strncasecompare("includesubdomains", p, 17)) {
if(gotinc)
return CURLE_BAD_FUNCTION_ARGUMENT;
subdomains = TRUE;
@@ -278,11 +277,11 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
if(ntail < hlen) {
size_t offs = hlen - ntail;
if((hostname[offs-1] == '.') &&
- Curl_strncasecompare(&hostname[offs], sts->host, ntail))
+ strncasecompare(&hostname[offs], sts->host, ntail))
return sts;
}
}
- if(Curl_strcasecompare(hostname, sts->host))
+ if(strcasecompare(hostname, sts->host))
return sts;
}
}
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index f57859e..1b75022 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -80,6 +80,7 @@
#include "http_proxy.h"
#include "warnless.h"
#include "http2.h"
+#include "cfilters.h"
#include "connect.h"
#include "strdup.h"
#include "altsvc.h"
@@ -101,18 +102,6 @@ static int http_getsock_do(struct Curl_easy *data,
curl_socket_t *socks);
static bool http_should_fail(struct Curl_easy *data);
-#ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct Curl_easy *data);
-#endif
-
-#ifdef USE_SSL
-static CURLcode https_connecting(struct Curl_easy *data, bool *done);
-static int https_getsock(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks);
-#else
-#define https_connecting(x,y) CURLE_COULDNT_CONNECT
-#endif
static CURLcode http_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
#ifdef USE_WEBSOCKETS
@@ -184,9 +173,9 @@ const struct Curl_handler Curl_handler_https = {
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
Curl_http_connect, /* connect_it */
- https_connecting, /* connecting */
+ NULL, /* connecting */
ZERO_NULL, /* doing */
- https_getsock, /* proto_getsock */
+ NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
@@ -209,9 +198,9 @@ const struct Curl_handler Curl_handler_wss = {
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
Curl_http_connect, /* connect_it */
- https_connecting, /* connecting */
+ NULL, /* connecting */
ZERO_NULL, /* doing */
- https_getsock, /* proto_getsock */
+ NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
@@ -229,6 +218,41 @@ const struct Curl_handler Curl_handler_wss = {
#endif
+static CURLcode h3_setup_conn(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+#ifdef ENABLE_QUIC
+ /* We want HTTP/3 directly, setup the filter chain ourself,
+ * overriding the default behaviour. */
+ DEBUGASSERT(conn->transport == TRNSPRT_QUIC);
+
+ if(!(conn->handler->flags & PROTOPT_SSL)) {
+ failf(data, "HTTP/3 requested for non-HTTPS URL");
+ return CURLE_URL_MALFORMAT;
+ }
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.socksproxy) {
+ failf(data, "HTTP/3 is not supported over a SOCKS proxy");
+ return CURLE_URL_MALFORMAT;
+ }
+ if(conn->bits.httpproxy && conn->bits.tunnel_proxy) {
+ failf(data, "HTTP/3 is not supported over a HTTP proxy");
+ return CURLE_URL_MALFORMAT;
+ }
+#endif
+
+ DEBUGF(infof(data, "HTTP/3 direct conn setup(conn #%ld, index=%d)",
+ conn->connection_id, FIRSTSOCKET));
+ return Curl_conn_socket_set(data, conn, FIRSTSOCKET);
+
+#else /* ENABLE_QUIC */
+ (void)conn;
+ (void)data;
+ DEBUGF(infof(data, "QUIC is not supported in this build"));
+ return CURLE_NOT_BUILT_IN;
+#endif /* !ENABLE_QUIC */
+}
+
static CURLcode http_setup_conn(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -241,18 +265,15 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
if(!http)
return CURLE_OUT_OF_MEMORY;
- Curl_mime_initpart(&http->form, data);
+ Curl_mime_initpart(&http->form);
data->req.p.http = http;
if(data->state.httpwant == CURL_HTTP_VERSION_3) {
- if(conn->handler->flags & PROTOPT_SSL)
- /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
- the QUIC dance. */
- conn->transport = TRNSPRT_QUIC;
- else {
- failf(data, "HTTP/3 requested for non-HTTPS URL");
- return CURLE_URL_MALFORMAT;
- }
+ conn->transport = TRNSPRT_QUIC;
+ }
+
+ if(conn->transport == TRNSPRT_QUIC) {
+ return h3_setup_conn(data, conn);
}
else {
if(!CONN_INUSE(conn))
@@ -555,7 +576,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
}
}
- conn->bits.rewindaftersend = FALSE; /* default */
+ data->state.rewindbeforesend = FALSE; /* default */
if((expectsend == -1) || (expectsend > bytessent)) {
#if defined(USE_NTLM)
@@ -572,8 +593,8 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
/* rewind data when completely done sending! */
if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
- conn->bits.rewindaftersend = TRUE;
- infof(data, "Rewind stream after send");
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Rewind stream before next send");
}
return CURLE_OK;
@@ -600,8 +621,8 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
/* rewind data when completely done sending! */
if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
- conn->bits.rewindaftersend = TRUE;
- infof(data, "Rewind stream after send");
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Rewind stream before next send");
}
return CURLE_OK;
@@ -625,9 +646,11 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
closure so we can safely do the rewind right now */
}
- if(bytessent)
- /* we rewind now at once since if we already sent something */
- return Curl_readrewind(data);
+ if(bytessent) {
+ /* mark for rewind since if we already sent something */
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Please rewind output before next send");
+ }
return CURLE_OK;
}
@@ -650,7 +673,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if(!data->set.str[STRING_BEARER])
authmask &= (unsigned long)~CURLAUTH_BEARER;
- if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
+ if(100 <= data->req.httpcode && data->req.httpcode <= 199)
/* this is a transient response code, ignore */
return CURLE_OK;
@@ -684,7 +707,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if(pickhost || pickproxy) {
if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD) &&
- !conn->bits.rewindaftersend) {
+ !data->state.rewindbeforesend) {
result = http_perhapsrewind(data, conn);
if(result)
return result;
@@ -1241,7 +1264,7 @@ static size_t readmoredata(char *buffer,
/* nothing to return */
return 0;
- /* make sure that a HTTP request is never sent away chunked! */
+ /* make sure that an HTTP request is never sent away chunked! */
data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
if(data->set.max_send_speed &&
@@ -1539,48 +1562,13 @@ Curl_compareheader(const char *headerline, /* line to check */
*/
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
{
- CURLcode result;
struct connectdata *conn = data->conn;
/* We default to persistent connections. We set this already in this connect
function to make the re-use checks properly be able to check this bit. */
connkeep(conn, "HTTP default");
-#ifndef CURL_DISABLE_PROXY
- /* the CONNECT procedure might not have been completed */
- result = Curl_proxy_connect(data, FIRSTSOCKET);
- if(result)
- return result;
-
- if(conn->bits.proxy_connect_closed)
- /* this is not an error, just part of the connection negotiation */
- return CURLE_OK;
-
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
-
- if(Curl_connect_ongoing(conn))
- /* nothing else to do except wait right now - we're not done here. */
- return CURLE_OK;
-
- if(data->set.haproxyprotocol) {
- /* add HAProxy PROXY protocol header */
- result = add_haproxy_protocol_header(data);
- if(result)
- return result;
- }
-#endif
-
- if(conn->given->flags & PROTOPT_SSL) {
- /* perform SSL initialization */
- result = https_connecting(data, done);
- if(result)
- return result;
- }
- else
- *done = TRUE;
-
- return CURLE_OK;
+ return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
}
/* this returns the socket to wait for in the DO and DOING state for the multi
@@ -1596,75 +1584,6 @@ static int http_getsock_do(struct Curl_easy *data,
return GETSOCK_WRITESOCK(0);
}
-#ifndef CURL_DISABLE_PROXY
-static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
-{
- struct dynbuf req;
- CURLcode result;
- const char *tcp_version;
- DEBUGASSERT(data->conn);
- Curl_dyn_init(&req, DYN_HAXPROXY);
-
-#ifdef USE_UNIX_SOCKETS
- if(data->conn->unix_domain_socket)
- /* the buffer is large enough to hold this! */
- result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
- else {
-#endif
- /* Emit the correct prefix for IPv6 */
- tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
-
- result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
- tcp_version,
- data->info.conn_local_ip,
- data->info.conn_primary_ip,
- data->info.conn_local_port,
- data->info.conn_primary_port);
-
-#ifdef USE_UNIX_SOCKETS
- }
-#endif
-
- if(!result)
- result = Curl_buffer_send(&req, data, &data->info.request_size,
- 0, FIRSTSOCKET);
- return result;
-}
-#endif
-
-#ifdef USE_SSL
-static CURLcode https_connecting(struct Curl_easy *data, bool *done)
-{
- CURLcode result;
- struct connectdata *conn = data->conn;
- DEBUGASSERT((data) && (data->conn->handler->flags & PROTOPT_SSL));
-
-#ifdef ENABLE_QUIC
- if(conn->transport == TRNSPRT_QUIC) {
- *done = TRUE;
- return CURLE_OK;
- }
-#endif
-
- /* perform SSL initialization for this socket */
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET, done);
- if(result)
- connclose(conn, "Failed HTTPS connection");
-
- return result;
-}
-
-static int https_getsock(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks)
-{
- (void)data;
- if(conn->handler->flags & PROTOPT_SSL)
- return Curl_ssl->getsock(conn, socks);
- return GETSOCK_BLANK;
-}
-#endif /* USE_SSL */
-
/*
* Curl_http_done() gets called after a single HTTP request has been
* performed.
@@ -2096,7 +2015,7 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
if(data->set.str[STRING_CUSTOMREQUEST])
request = data->set.str[STRING_CUSTOMREQUEST];
else {
- if(data->set.opt_no_body)
+ if(data->req.no_body)
request = "HEAD";
else {
DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD));
@@ -2141,7 +2060,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
{
const char *ptr;
if(!data->state.this_is_a_follow) {
- /* Free to avoid leaking memory on multiple requests*/
+ /* Free to avoid leaking memory on multiple requests */
free(data->state.first_host);
data->state.first_host = strdup(conn->host.name);
@@ -2384,7 +2303,7 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
cthdr = "multipart/form-data";
curl_mime_headers(http->sendit, data->set.headers, 0);
- result = Curl_mime_prepare_headers(http->sendit, cthdr,
+ result = Curl_mime_prepare_headers(data, http->sendit, cthdr,
NULL, MIMESTRATEGY_FORM);
curl_mime_headers(http->sendit, NULL, 0);
if(!result)
@@ -2795,7 +2714,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
- !strcmp(host, "[::1]") ? TRUE : FALSE;
+ !strcmp(host, "::1") ? TRUE : FALSE;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
secure_context);
@@ -2925,8 +2844,8 @@ CURLcode Curl_http_resume(struct Curl_easy *data,
data->state.resume_from = 0;
}
- if(data->state.resume_from && !data->state.this_is_a_follow) {
- /* do we still game? */
+ if(data->state.resume_from && !data->state.followlocation) {
+ /* only act on the first request */
/* Now, let's read off the proper amount of bytes from the
input. */
@@ -3027,14 +2946,14 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
if(data->set.timecondition && !data->state.range) {
/* A time condition has been set AND no ranges have been requested. This
seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
- action for a HTTP/1.1 client */
+ action for an HTTP/1.1 client */
if(!Curl_meets_timecondition(data, k->timeofdoc)) {
*done = TRUE;
- /* We're simulating a http 304 from server so we return
+ /* We're simulating an HTTP 304 from server so we return
what should have been returned from the server */
data->info.httpcode = 304;
- infof(data, "Simulate a HTTP 304 response");
+ infof(data, "Simulate an HTTP 304 response");
/* we abort the transfer before it is completed == we ruin the
re-use ability. Close the connection */
streamclose(conn, "Simulated 304 handling");
@@ -3080,7 +2999,7 @@ CURLcode Curl_transferencode(struct Curl_easy *data)
#ifndef USE_HYPER
/*
- * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * Curl_http() gets called from the generic multi_do() function when an HTTP
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
@@ -3117,7 +3036,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* continue with HTTP/1.1 when explicitly requested */
break;
default:
- /* Check if user wants to use HTTP/2 with clear TCP*/
+ /* Check if user wants to use HTTP/2 with clear TCP */
#ifdef USE_NGHTTP2
if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
@@ -3140,7 +3059,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
}
else {
- /* prepare for a http2 request */
+ /* prepare for an http2 request */
result = Curl_http2_setup(data, conn);
if(result)
return result;
@@ -3497,7 +3416,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
STRCONST("Proxy-Connection:"),
STRCONST("keep-alive"))) {
/*
- * When a HTTP/1.0 reply comes when using a proxy, the
+ * When an HTTP/1.0 reply comes when using a proxy, the
* 'Proxy-Connection: keep-alive' line tells us the
* connection will be kept alive for our pleasure.
* Default action for 1.0 is to close.
@@ -3511,7 +3430,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
STRCONST("Proxy-Connection:"),
STRCONST("close"))) {
/*
- * We get a HTTP/1.1 response from a proxy and it says it'll
+ * We get an HTTP/1.1 response from a proxy and it says it'll
* close down after this transfer.
*/
connclose(conn, "Proxy-Connection: asked to close after done");
@@ -3523,7 +3442,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
STRCONST("Connection:"),
STRCONST("keep-alive"))) {
/*
- * A HTTP/1.0 reply with the 'Connection: keep-alive' line
+ * An HTTP/1.0 reply with the 'Connection: keep-alive' line
* tells us the connection will be kept alive for our
* pleasure. Default action for 1.0 is to close.
*
@@ -3634,7 +3553,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
- !strcmp(host, "[::1]") ? TRUE : FALSE;
+ !strcmp(host, "::1") ? TRUE : FALSE;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
@@ -3708,6 +3627,9 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
result = http_perhapsrewind(data, conn);
if(result)
return result;
+
+ /* mark the next request as a followed location: */
+ data->state.this_is_a_follow = TRUE;
}
}
}
@@ -3724,7 +3646,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
#endif
)) {
CURLcode check =
- Curl_hsts_parse(data->hsts, data->state.up.hostname,
+ Curl_hsts_parse(data->hsts, conn->host.name,
headp + strlen("Strict-Transport-Security:"));
if(check)
infof(data, "Illegal STS header skipped");
@@ -3751,7 +3673,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
result = Curl_altsvc_parse(data, data->asi,
headp + strlen("Alt-Svc:"),
id, conn->host.name,
- curlx_uitous(conn->remote_port));
+ curlx_uitous((unsigned int)conn->remote_port));
if(result)
return result;
}
@@ -4012,7 +3934,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
switch(k->httpcode) {
case 100:
/*
- * We have made a HTTP PUT or POST and this is 1.1-lingo
+ * We have made an HTTP PUT or POST and this is 1.1-lingo
* that tells us that the server is OK with this and ready
* to receive the data.
* However, we'll get more headers now so we must get
@@ -4176,7 +4098,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(k->httpcode >= 300) {
if((!conn->bits.authneg) && !conn->bits.close &&
- !conn->bits.rewindaftersend) {
+ !data->state.rewindbeforesend) {
/*
* General treatment of errors when about to send data. Including :
* "417 Expectation Failed", while waiting for 100-continue.
@@ -4186,7 +4108,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* something else should've considered the big picture and we
* avoid this check.
*
- * rewindaftersend indicates that something has told libcurl to
+ * rewindbeforesend indicates that something has told libcurl to
* continue sending even if it gets discarded
*/
@@ -4235,9 +4157,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
- if(conn->bits.rewindaftersend) {
- /* We rewind after a complete send, so thus we continue
- sending now */
+ if(data->state.rewindbeforesend &&
+ (conn->writesockfd != CURL_SOCKET_BAD)) {
+ /* We rewind before next send, continue sending now */
infof(data, "Keep sending data to get tossed away");
k->keepon |= KEEP_SEND;
}
@@ -4250,7 +4172,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* If we requested a "no body", this is a good time to get
* out and return home.
*/
- if(data->set.opt_no_body)
+ if(data->req.no_body)
*stop_reading = TRUE;
#ifndef CURL_DISABLE_RTSP
else if((conn->handler->protocol & CURLPROTO_RTSP) &&
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index f7cbb34..ecfe4ee 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -317,7 +317,7 @@ struct http_conn {
uint8_t binsettings[H2_BINSETTINGS_LEN];
size_t binlen; /* length of the binsettings data */
- /* We associate the connnectdata struct with the connection, but we need to
+ /* We associate the connectdata struct with the connection, but we need to
make sure we can identify the current "driving" transfer. This is a
work-around for the lack of nghttp2_session_set_user_data() in older
nghttp2 versions that we want to support. (Added in 1.31.0) */
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index b7409b0..b9d3245 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -109,7 +109,7 @@ static int http2_getsock(struct Curl_easy *data,
sock[0] = conn->sock[FIRSTSOCKET];
if(!(k->keepon & KEEP_RECV_PAUSE))
- /* Unless paused - in a HTTP/2 connection we can basically always get a
+ /* Unless paused - in an HTTP/2 connection we can basically always get a
frame so we should always be ready for one */
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
@@ -191,7 +191,7 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
}
else if(sval & CURL_CSELECT_IN) {
/* readable with no error. could still be closed */
- dead = !Curl_connalive(conn);
+ dead = !Curl_connalive(data, conn);
if(!dead) {
/* This happens before we've sent off a request and the connection is
not in use by any other transfer, there shouldn't be any data here,
@@ -1024,9 +1024,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!check)
/* no memory */
return NGHTTP2_ERR_CALLBACK_FAILURE;
- if(!Curl_strcasecompare(check, (const char *)value) &&
+ if(!strcasecompare(check, (const char *)value) &&
((conn->remote_port != conn->given->defport) ||
- !Curl_strcasecompare(conn->host.name, (const char *)value))) {
+ !strcasecompare(conn->host.name, (const char *)value))) {
/* This is push is not for the same authority that was asked for in
* the URL. RFC 7540 section 8.2 says: "A client MUST treat a
* PUSH_PROMISE for which the server is not authoritative as a stream
@@ -1120,7 +1120,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
- /* convert to a HTTP1-style header */
+ /* convert to an HTTP1-style header */
result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1351,7 +1351,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
}
/*
- * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
+ * Append headers to ask for an HTTP1.1 to HTTP2 upgrade.
*/
CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
struct Curl_easy *data)
@@ -2307,7 +2307,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
Curl_http2_remove_child(data->set.stream_depends_on, data);
}
-/* Only call this function for a transfer that already got a HTTP/2
+/* Only call this function for a transfer that already got an HTTP/2
CURLE_HTTP2_STREAM error! */
bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h
index f039059..966bf75 100644
--- a/Utilities/cmcurl/lib/http2.h
+++ b/Utilities/cmcurl/lib/http2.h
@@ -73,7 +73,7 @@ bool Curl_h2_http_1_1_error(struct Curl_easy *data);
#define Curl_http2_init_state(x)
#define Curl_http2_init_userset(x)
#define Curl_http2_done(x,y)
-#define Curl_http2_done_sending(x,y)
+#define Curl_http2_done_sending(x,y) (void)y
#define Curl_http2_add_child(x, y, z)
#define Curl_http2_remove_child(x, y)
#define Curl_http2_cleanup_dependencies(x)
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 440eb38..8c6d1c9 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -32,8 +32,6 @@
#include "http_aws_sigv4.h"
#include "curl_sha256.h"
#include "transfer.h"
-
-#include "strcase.h"
#include "parsedate.h"
#include "sendf.h"
@@ -118,7 +116,7 @@ static void trim_headers(struct curl_slist *head)
}
}
-/* maximum lenth for the aws sivg4 parts */
+/* maximum length for the aws sivg4 parts */
#define MAX_SIGV4_LEN 64
#define MAX_SIGV4_LEN_TXT "64"
@@ -268,6 +266,40 @@ fail:
return ret;
}
+#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
+
+/* try to parse a payload hash from the content-sha256 header */
+static char *parse_content_sha_hdr(struct Curl_easy *data,
+ const char *provider1,
+ size_t *value_len)
+{
+ char key[CONTENT_SHA256_KEY_LEN];
+ size_t key_len;
+ char *value;
+ size_t len;
+
+ key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1);
+
+ value = Curl_checkheaders(data, key, key_len);
+ if(!value)
+ return NULL;
+
+ value = strchr(value, ':');
+ if(!value)
+ return NULL;
+ ++value;
+
+ while(*value && ISBLANK(*value))
+ ++value;
+
+ len = strlen(value);
+ while(len > 0 && ISBLANK(value[len-1]))
+ --len;
+
+ *value_len = len;
+ return value;
+}
+
CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
{
CURLcode ret = CURLE_OUT_OF_MEMORY;
@@ -286,6 +318,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
struct dynbuf canonical_headers;
struct dynbuf signed_headers;
char *date_header = NULL;
+ char *payload_hash = NULL;
+ size_t payload_hash_len = 0;
const char *post_data = data->set.postfields;
size_t post_data_len = 0;
unsigned char sha_hash[32];
@@ -308,7 +342,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
return CURLE_OK;
}
- /* we init thoses buffers here, so goto fail will free initialized dynbuf */
+ /* we init those buffers here, so goto fail will free initialized dynbuf */
Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
@@ -403,17 +437,23 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
memcpy(date, timestamp, sizeof(date));
date[sizeof(date) - 1] = 0;
- if(post_data) {
- if(data->set.postfieldsize < 0)
- post_data_len = strlen(post_data);
- else
- post_data_len = (size_t)data->set.postfieldsize;
- }
- if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
- post_data_len))
- goto fail;
+ payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
- sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+ if(!payload_hash) {
+ if(post_data) {
+ if(data->set.postfieldsize < 0)
+ post_data_len = strlen(post_data);
+ else
+ post_data_len = (size_t)data->set.postfieldsize;
+ }
+ if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
+ post_data_len))
+ goto fail;
+
+ sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+ payload_hash = sha_hex;
+ payload_hash_len = strlen(sha_hex);
+ }
{
Curl_HttpReq httpreq;
@@ -427,13 +467,13 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
"%s\n" /* CanonicalQueryString */
"%s\n" /* CanonicalHeaders */
"%s\n" /* SignedHeaders */
- "%s", /* HashedRequestPayload in hex */
+ "%.*s", /* HashedRequestPayload in hex */
method,
data->state.up.path,
data->state.up.query ? data->state.up.query : "",
Curl_dyn_ptr(&canonical_headers),
Curl_dyn_ptr(&signed_headers),
- sha_hex);
+ (int)payload_hash_len, payload_hash);
if(!canonical_request)
goto fail;
}
@@ -460,7 +500,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
/*
* Google allows using RSA key instead of HMAC, so this code might change
- * in the future. For now we ony support HMAC.
+ * in the future. For now we only support HMAC.
*/
str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
"%s\n" /* RequestDateTime */
diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c
index 0b83685..c344e6d 100644
--- a/Utilities/cmcurl/lib/http_chunks.c
+++ b/Utilities/cmcurl/lib/http_chunks.c
@@ -113,7 +113,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
*wrote = 0; /* nothing's written yet */
/* the original data is written to the client, but we go on with the
- chunk read process, to properly calculate the content length*/
+ chunk read process, to properly calculate the content length */
if(data->set.http_te_skip && !k->ignorebody) {
result = Curl_client_write(data, CLIENTWRITE_BODY, datap, datalen);
if(result) {
diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c
index a71c6b7..f015f78 100644
--- a/Utilities/cmcurl/lib/http_digest.c
+++ b/Utilities/cmcurl/lib/http_digest.c
@@ -81,7 +81,7 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
bool have_chlg;
/* Point to the address of the pointer that holds the string to send to the
- server, which is for a plain host or for a HTTP proxy */
+ server, which is for a plain host or for an HTTP proxy */
char **allocuserpwd;
/* Point to the name and password for this */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index 5a6a977..a19cc0d 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -134,7 +134,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
struct bufref ntlmmsg;
/* point to the address of the pointer that holds the string to send to the
- server, which is for a plain host or for a HTTP proxy */
+ server, which is for a plain host or for an HTTP proxy */
char **allocuserpwd;
/* point to the username, password, service and host */
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index cc20b3a..e30730a 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -37,6 +37,7 @@
#include "url.h"
#include "select.h"
#include "progress.h"
+#include "cfilters.h"
#include "connect.h"
#include "curlx.h"
#include "vtls/vtls.h"
@@ -48,179 +49,192 @@
#include "curl_memory.h"
#include "memdebug.h"
-/*
- * Perform SSL initialization for HTTPS proxy. Sets
- * proxy_ssl_connected connection bit when complete. Can be
- * called multiple times.
- */
-static CURLcode https_proxy_connect(struct Curl_easy *data, int sockindex)
+typedef enum {
+ TUNNEL_INIT, /* init/default/no tunnel state */
+ TUNNEL_CONNECT, /* CONNECT request is being send */
+ TUNNEL_RECEIVE, /* CONNECT answer is being received */
+ TUNNEL_RESPONSE, /* CONNECT response received completely */
+ TUNNEL_ESTABLISHED,
+ TUNNEL_FAILED
+} tunnel_state;
+
+/* struct for HTTP CONNECT tunneling */
+struct tunnel_state {
+ int sockindex;
+ const char *hostname;
+ int remote_port;
+ struct HTTP http_proxy;
+ struct HTTP *prot_save;
+ struct dynbuf rcvbuf;
+ struct dynbuf req;
+ size_t nsend;
+ size_t headerlines;
+ enum keeponval {
+ KEEPON_DONE,
+ KEEPON_CONNECT,
+ KEEPON_IGNORE
+ } keepon;
+ curl_off_t cl; /* size of content to read and ignore */
+ tunnel_state tunnel_state;
+ BIT(chunked_encoding);
+ BIT(close_connection);
+};
+
+
+static bool tunnel_is_established(struct tunnel_state *ts)
{
-#ifdef USE_SSL
- struct connectdata *conn = data->conn;
- CURLcode result = CURLE_OK;
- DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS);
- if(!conn->bits.proxy_ssl_connected[sockindex]) {
- /* perform SSL initialization for this socket */
- result =
- Curl_ssl_connect_nonblocking(data, conn, TRUE, sockindex,
- &conn->bits.proxy_ssl_connected[sockindex]);
- if(result)
- /* a failed connection is marked for closure to prevent (bad) re-use or
- similar */
- connclose(conn, "TLS handshake failed");
- }
- return result;
-#else
- (void) data;
- (void) sockindex;
- return CURLE_NOT_BUILT_IN;
-#endif
+ return ts && (ts->tunnel_state == TUNNEL_ESTABLISHED);
}
-CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
+static bool tunnel_is_failed(struct tunnel_state *ts)
{
- struct connectdata *conn = data->conn;
- if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
- const CURLcode result = https_proxy_connect(data, sockindex);
- if(result)
- return result;
- if(!conn->bits.proxy_ssl_connected[sockindex])
- return result; /* wait for HTTPS proxy SSL initialization to complete */
- }
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
-#ifndef CURL_DISABLE_PROXY
- /* for [protocol] tunneled through HTTP proxy */
- const char *hostname;
- int remote_port;
- CURLcode result;
-
- /* We want "seamless" operations through HTTP proxy tunnel */
-
- /* for the secondary socket (FTP), use the "connect to host"
- * but ignore the "connect to port" (use the secondary port)
- */
-
- if(conn->bits.conn_to_host)
- hostname = conn->conn_to_host.name;
- else if(sockindex == SECONDARYSOCKET)
- hostname = conn->secondaryhostname;
- else
- hostname = conn->host.name;
-
- if(sockindex == SECONDARYSOCKET)
- remote_port = conn->secondary_port;
- else if(conn->bits.conn_to_port)
- remote_port = conn->conn_to_port;
- else
- remote_port = conn->remote_port;
-
- result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
- if(CURLE_OK != result)
- return result;
- Curl_safefree(data->state.aptr.proxyuserpwd);
-#else
- return CURLE_NOT_BUILT_IN;
-#endif
- }
- /* no HTTP tunnel proxy, just return */
- return CURLE_OK;
+ return ts && (ts->tunnel_state == TUNNEL_FAILED);
}
-bool Curl_connect_complete(struct connectdata *conn)
+static CURLcode tunnel_reinit(struct tunnel_state *ts,
+ struct connectdata *conn,
+ struct Curl_easy *data)
{
- return !conn->connect_state ||
- (conn->connect_state->tunnel_state >= TUNNEL_COMPLETE);
-}
+ (void)data;
+ DEBUGASSERT(ts);
+ Curl_dyn_reset(&ts->rcvbuf);
+ Curl_dyn_reset(&ts->req);
+ ts->tunnel_state = TUNNEL_INIT;
+ ts->keepon = KEEPON_CONNECT;
+ ts->cl = 0;
+ ts->close_connection = FALSE;
+
+ if(conn->bits.conn_to_host)
+ ts->hostname = conn->conn_to_host.name;
+ else if(ts->sockindex == SECONDARYSOCKET)
+ ts->hostname = conn->secondaryhostname;
+ else
+ ts->hostname = conn->host.name;
+
+ if(ts->sockindex == SECONDARYSOCKET)
+ ts->remote_port = conn->secondary_port;
+ else if(conn->bits.conn_to_port)
+ ts->remote_port = conn->conn_to_port;
+ else
+ ts->remote_port = conn->remote_port;
-bool Curl_connect_ongoing(struct connectdata *conn)
-{
- return conn->connect_state &&
- (conn->connect_state->tunnel_state <= TUNNEL_COMPLETE);
+ return CURLE_OK;
}
-/* when we've sent a CONNECT to a proxy, we should rather either wait for the
- socket to become readable to be able to get the response headers or if
- we're still sending the request, wait for write. */
-int Curl_connect_getsock(struct connectdata *conn)
+static CURLcode tunnel_init(struct tunnel_state **pts,
+ struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
{
- struct HTTP *http;
- DEBUGASSERT(conn);
- DEBUGASSERT(conn->connect_state);
- http = &conn->connect_state->http_proxy;
-
- if(http->sending == HTTPSEND_REQUEST)
- return GETSOCK_WRITESOCK(0);
-
- return GETSOCK_READSOCK(0);
-}
+ struct tunnel_state *ts;
+ CURLcode result;
-static CURLcode connect_init(struct Curl_easy *data, bool reinit)
-{
- struct http_connect_state *s;
- struct connectdata *conn = data->conn;
if(conn->handler->flags & PROTOPT_NOTCPPROXY) {
failf(data, "%s cannot be done over CONNECT", conn->handler->scheme);
return CURLE_UNSUPPORTED_PROTOCOL;
}
- if(!reinit) {
- CURLcode result;
- DEBUGASSERT(!conn->connect_state);
- /* we might need the upload buffer for streaming a partial request */
- result = Curl_get_upload_buffer(data);
- if(result)
- return result;
- s = calloc(1, sizeof(struct http_connect_state));
- if(!s)
- return CURLE_OUT_OF_MEMORY;
- infof(data, "allocate connect buffer");
- conn->connect_state = s;
- Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
-
- /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
- * member conn->proto.http; we want [protocol] through HTTP and we have
- * to change the member temporarily for connecting to the HTTP
- * proxy. After Curl_proxyCONNECT we have to set back the member to the
- * original pointer
- *
- * This function might be called several times in the multi interface case
- * if the proxy's CONNECT response is not instant.
- */
- s->prot_save = data->req.p.http;
- data->req.p.http = &s->http_proxy;
- connkeep(conn, "HTTP proxy CONNECT");
- }
- else {
- DEBUGASSERT(conn->connect_state);
- s = conn->connect_state;
- Curl_dyn_reset(&s->rcvbuf);
- }
- s->tunnel_state = TUNNEL_INIT;
- s->keepon = KEEPON_CONNECT;
- s->cl = 0;
- s->close_connection = FALSE;
- return CURLE_OK;
+ /* we might need the upload buffer for streaming a partial request */
+ result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+
+ ts = calloc(1, sizeof(*ts));
+ if(!ts)
+ return CURLE_OUT_OF_MEMORY;
+
+ ts->sockindex = sockindex;
+ infof(data, "allocate connect buffer");
+
+ Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
+ Curl_dyn_init(&ts->req, DYN_HTTP_REQUEST);
+
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
+ * member conn->proto.http; we want [protocol] through HTTP and we have
+ * to change the member temporarily for connecting to the HTTP
+ * proxy. After Curl_proxyCONNECT we have to set back the member to the
+ * original pointer
+ *
+ * This function might be called several times in the multi interface case
+ * if the proxy's CONNECT response is not instant.
+ */
+ ts->prot_save = data->req.p.http;
+ data->req.p.http = &ts->http_proxy;
+ *pts = ts;
+ connkeep(conn, "HTTP proxy CONNECT");
+ return tunnel_reinit(ts, conn, data);
}
-void Curl_connect_done(struct Curl_easy *data)
+static void tunnel_go_state(struct Curl_cfilter *cf,
+ struct tunnel_state *ts,
+ tunnel_state new_state,
+ struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
- struct http_connect_state *s = conn->connect_state;
- if(s && (s->tunnel_state != TUNNEL_EXIT)) {
- s->tunnel_state = TUNNEL_EXIT;
- Curl_dyn_free(&s->rcvbuf);
- Curl_dyn_free(&s->req);
+ if(ts->tunnel_state == new_state)
+ return;
+ /* leaving this one */
+ switch(ts->tunnel_state) {
+ case TUNNEL_CONNECT:
+ data->req.ignorebody = FALSE;
+ break;
+ default:
+ break;
+ }
+ /* entering this one */
+ switch(new_state) {
+ case TUNNEL_INIT:
+ tunnel_reinit(ts, cf->conn, data);
+ break;
+
+ case TUNNEL_CONNECT:
+ ts->tunnel_state = TUNNEL_CONNECT;
+ ts->keepon = KEEPON_CONNECT;
+ Curl_dyn_reset(&ts->rcvbuf);
+ break;
+
+ case TUNNEL_RECEIVE:
+ ts->tunnel_state = TUNNEL_RECEIVE;
+ break;
+
+ case TUNNEL_RESPONSE:
+ ts->tunnel_state = TUNNEL_RESPONSE;
+ break;
+ case TUNNEL_ESTABLISHED:
+ infof(data, "CONNECT phase completed");
+ data->state.authproxy.done = TRUE;
+ data->state.authproxy.multipass = FALSE;
+ /* FALLTHROUGH */
+ case TUNNEL_FAILED:
+ ts->tunnel_state = new_state;
+ Curl_dyn_reset(&ts->rcvbuf);
+ Curl_dyn_reset(&ts->req);
/* restore the protocol pointer */
- data->req.p.http = s->prot_save;
+ data->req.p.http = ts->prot_save;
data->info.httpcode = 0; /* clear it as it might've been used for the
proxy */
- data->req.ignorebody = FALSE;
+ /* If a proxy-authorization header was used for the proxy, then we should
+ make sure that it isn't accidentally used for the document request
+ after we've connected. So let's free and clear it here. */
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+ data->state.aptr.proxyuserpwd = NULL;
#ifdef USE_HYPER
data->state.hconnect = FALSE;
#endif
- infof(data, "CONNECT phase completed");
+ break;
+ }
+}
+
+static void tunnel_free(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct tunnel_state *ts = cf->ctx;
+ if(ts) {
+ tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
+ Curl_dyn_free(&ts->rcvbuf);
+ Curl_dyn_free(&ts->req);
+ free(ts);
+ cf->ctx = NULL;
}
}
@@ -257,821 +271,1013 @@ static CURLcode CONNECT_host(struct Curl_easy *data,
}
#ifndef USE_HYPER
-static CURLcode CONNECT(struct Curl_easy *data,
- int sockindex,
- const char *hostname,
- int remote_port)
+static CURLcode start_CONNECT(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts)
{
- int subversion = 0;
- struct SingleRequest *k = &data->req;
+ char *hostheader = NULL;
+ char *host = NULL;
+ const char *httpv;
CURLcode result;
- struct connectdata *conn = data->conn;
- curl_socket_t tunnelsocket = conn->sock[sockindex];
- struct http_connect_state *s = conn->connect_state;
- struct HTTP *http = data->req.p.http;
- char *linep;
- size_t perline;
-#define SELECT_OK 0
-#define SELECT_ERROR 1
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
+ ts->hostname, ts->remote_port);
+
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ Curl_safefree(data->req.newurl);
+
+ result = CONNECT_host(data, conn,
+ ts->hostname, ts->remote_port,
+ &hostheader, &host);
+ if(result)
+ goto out;
+
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+ hostheader, TRUE);
+ if(result)
+ goto out;
+
+ httpv = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
+
+ result =
+ Curl_dyn_addf(&ts->req,
+ "CONNECT %s HTTP/%s\r\n"
+ "%s" /* Host: */
+ "%s", /* Proxy-Authorization */
+ hostheader,
+ httpv,
+ host?host:"",
+ data->state.aptr.proxyuserpwd?
+ data->state.aptr.proxyuserpwd:"");
+ if(result)
+ goto out;
+
+ if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent"))
+ && data->set.str[STRING_USERAGENT])
+ result = Curl_dyn_addf(&ts->req, "User-Agent: %s\r\n",
+ data->set.str[STRING_USERAGENT]);
+ if(result)
+ goto out;
+
+ if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection")))
+ result = Curl_dyn_addn(&ts->req,
+ STRCONST("Proxy-Connection: Keep-Alive\r\n"));
+ if(result)
+ goto out;
+
+ result = Curl_add_custom_headers(data, TRUE, &ts->req);
+ if(result)
+ goto out;
+
+ /* CRLF terminate the request */
+ result = Curl_dyn_addn(&ts->req, STRCONST("\r\n"));
+ if(result)
+ goto out;
+
+ /* Send the connect request to the proxy */
+ result = Curl_buffer_send(&ts->req, data, &data->info.request_size, 0,
+ ts->sockindex);
+ ts->headerlines = 0;
+
+out:
+ if(result)
+ failf(data, "Failed sending CONNECT to proxy");
+ free(host);
+ free(hostheader);
+ return result;
+}
- if(Curl_connect_complete(conn))
- return CURLE_OK; /* CONNECT is already completed */
+static CURLcode send_CONNECT(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts,
+ bool *done)
+{
+ struct SingleRequest *k = &data->req;
+ struct HTTP *http = data->req.p.http;
+ CURLcode result = CURLE_OK;
- conn->bits.proxy_connect_closed = FALSE;
+ if(http->sending != HTTPSEND_REQUEST)
+ goto out;
- do {
- timediff_t check;
- if(TUNNEL_INIT == s->tunnel_state) {
- /* BEGIN CONNECT PHASE */
- struct dynbuf *req = &s->req;
- char *hostheader = NULL;
- char *host = NULL;
+ if(!ts->nsend) {
+ size_t fillcount;
+ k->upload_fromhere = data->state.ulbuf;
+ result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
+ &fillcount);
+ if(result)
+ goto out;
+ ts->nsend = fillcount;
+ }
+ if(ts->nsend) {
+ ssize_t bytes_written;
+ /* write to socket (send away data) */
+ result = Curl_write(data,
+ conn->writesockfd, /* socket to send to */
+ k->upload_fromhere, /* buffer pointer */
+ ts->nsend, /* buffer size */
+ &bytes_written); /* actually sent */
+ if(result)
+ goto out;
+ /* send to debug callback! */
+ Curl_debug(data, CURLINFO_HEADER_OUT,
+ k->upload_fromhere, bytes_written);
- infof(data, "Establish HTTP proxy tunnel to %s:%d",
- hostname, remote_port);
+ ts->nsend -= bytes_written;
+ k->upload_fromhere += bytes_written;
+ }
+ if(!ts->nsend)
+ http->sending = HTTPSEND_NADA;
- /* This only happens if we've looped here due to authentication
- reasons, and we don't really use the newly cloned URL here
- then. Just free() it. */
- Curl_safefree(data->req.newurl);
+out:
+ if(result)
+ failf(data, "Failed sending CONNECT to proxy");
+ *done = (http->sending != HTTPSEND_REQUEST);
+ return result;
+}
- /* initialize send-buffer */
- Curl_dyn_init(req, DYN_HTTP_REQUEST);
+static CURLcode on_resp_header(struct Curl_easy *data,
+ struct tunnel_state *ts,
+ const char *header)
+{
+ CURLcode result = CURLE_OK;
+ struct SingleRequest *k = &data->req;
+ int subversion = 0;
- result = CONNECT_host(data, conn,
- hostname, remote_port, &hostheader, &host);
- if(result)
- return result;
+ if((checkprefix("WWW-Authenticate:", header) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", header) &&
+ (407 == k->httpcode))) {
- /* Setup the proxy-authorization header, if any */
- result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
- hostheader, TRUE);
-
- if(!result) {
- const char *httpv =
- (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
-
- result =
- Curl_dyn_addf(req,
- "CONNECT %s HTTP/%s\r\n"
- "%s" /* Host: */
- "%s", /* Proxy-Authorization */
- hostheader,
- httpv,
- host?host:"",
- data->state.aptr.proxyuserpwd?
- data->state.aptr.proxyuserpwd:"");
-
- if(!result && !Curl_checkProxyheaders(data,
- conn, STRCONST("User-Agent")) &&
- data->set.str[STRING_USERAGENT])
- result = Curl_dyn_addf(req, "User-Agent: %s\r\n",
- data->set.str[STRING_USERAGENT]);
-
- if(!result && !Curl_checkProxyheaders(data, conn,
- STRCONST("Proxy-Connection")))
- result = Curl_dyn_addn(req,
- STRCONST("Proxy-Connection: Keep-Alive\r\n"));
-
- if(!result)
- result = Curl_add_custom_headers(data, TRUE, req);
-
- if(!result)
- /* CRLF terminate the request */
- result = Curl_dyn_addn(req, STRCONST("\r\n"));
-
- if(!result) {
- /* Send the connect request to the proxy */
- result = Curl_buffer_send(req, data, &data->info.request_size, 0,
- sockindex);
- s->headerlines = 0;
- }
- if(result)
- failf(data, "Failed sending CONNECT to proxy");
- }
- free(host);
- free(hostheader);
- if(result)
- return result;
+ bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+ char *auth = Curl_copy_header_value(header);
+ if(!auth)
+ return CURLE_OUT_OF_MEMORY;
- s->tunnel_state = TUNNEL_CONNECT;
- } /* END CONNECT PHASE */
+ DEBUGF(infof(data, "CONNECT: fwd auth header '%s'",
+ header));
+ result = Curl_http_input_auth(data, proxy, auth);
- check = Curl_timeleft(data, NULL, TRUE);
- if(check <= 0) {
- failf(data, "Proxy CONNECT aborted due to timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ free(auth);
+
+ if(result)
+ return result;
+ }
+ else if(checkprefix("Content-Length:", header)) {
+ if(k->httpcode/100 == 2) {
+ /* A client MUST ignore any Content-Length or Transfer-Encoding
+ header fields received in a successful response to CONNECT.
+ "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+ infof(data, "Ignoring Content-Length in CONNECT %03d response",
+ k->httpcode);
+ }
+ else {
+ (void)curlx_strtoofft(header + strlen("Content-Length:"),
+ NULL, 10, &ts->cl);
+ }
+ }
+ else if(Curl_compareheader(header,
+ STRCONST("Connection:"), STRCONST("close")))
+ ts->close_connection = TRUE;
+ else if(checkprefix("Transfer-Encoding:", header)) {
+ if(k->httpcode/100 == 2) {
+ /* A client MUST ignore any Content-Length or Transfer-Encoding
+ header fields received in a successful response to CONNECT.
+ "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+ infof(data, "Ignoring Transfer-Encoding in "
+ "CONNECT %03d response", k->httpcode);
}
+ else if(Curl_compareheader(header,
+ STRCONST("Transfer-Encoding:"),
+ STRCONST("chunked"))) {
+ infof(data, "CONNECT responded chunked");
+ ts->chunked_encoding = TRUE;
+ /* init our chunky engine */
+ Curl_httpchunk_init(data);
+ }
+ }
+ else if(Curl_compareheader(header,
+ STRCONST("Proxy-Connection:"),
+ STRCONST("close")))
+ ts->close_connection = TRUE;
+ else if(2 == sscanf(header, "HTTP/1.%d %d",
+ &subversion,
+ &k->httpcode)) {
+ /* store the HTTP code from the proxy */
+ data->info.httpproxycode = k->httpcode;
+ }
+ return result;
+}
+
+static CURLcode recv_CONNECT_resp(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts,
+ bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct SingleRequest *k = &data->req;
+ curl_socket_t tunnelsocket = conn->sock[ts->sockindex];
+ char *linep;
+ size_t perline;
+ int error;
+
+#define SELECT_OK 0
+#define SELECT_ERROR 1
+
+ error = SELECT_OK;
+ *done = FALSE;
+
+ if(!Curl_conn_data_pending(data, ts->sockindex))
+ return CURLE_OK;
+
+ while(ts->keepon) {
+ ssize_t gotbytes;
+ char byte;
- if(!Curl_conn_data_pending(conn, sockindex) && !http->sending)
- /* return so we'll be called again polling-style */
+ /* Read one byte at a time to avoid a race condition. Wait at most one
+ second before looping to ensure continuous pgrsUpdates. */
+ result = Curl_read(data, tunnelsocket, &byte, 1, &gotbytes);
+ if(result == CURLE_AGAIN)
+ /* socket buffer drained, return */
return CURLE_OK;
- /* at this point, the tunnel_connecting phase is over. */
-
- if(http->sending == HTTPSEND_REQUEST) {
- if(!s->nsend) {
- size_t fillcount;
- k->upload_fromhere = data->state.ulbuf;
- result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
- &fillcount);
- if(result)
- return result;
- s->nsend = fillcount;
+ if(Curl_pgrsUpdate(data))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ if(result) {
+ ts->keepon = KEEPON_DONE;
+ break;
+ }
+
+ if(gotbytes <= 0) {
+ if(data->set.proxyauth && data->state.authproxy.avail &&
+ data->state.aptr.proxyuserpwd) {
+ /* proxy auth was requested and there was proxy auth available,
+ then deem this as "mere" proxy disconnect */
+ ts->close_connection = TRUE;
+ infof(data, "Proxy CONNECT connection closed");
}
- if(s->nsend) {
- ssize_t bytes_written;
- /* write to socket (send away data) */
- result = Curl_write(data,
- conn->writesockfd, /* socket to send to */
- k->upload_fromhere, /* buffer pointer */
- s->nsend, /* buffer size */
- &bytes_written); /* actually sent */
-
- if(!result)
- /* send to debug callback! */
- Curl_debug(data, CURLINFO_HEADER_OUT,
- k->upload_fromhere, bytes_written);
-
- s->nsend -= bytes_written;
- k->upload_fromhere += bytes_written;
- return result;
+ else {
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted");
}
- http->sending = HTTPSEND_NADA;
- /* if nothing left to send, continue */
+ ts->keepon = KEEPON_DONE;
+ break;
}
- { /* READING RESPONSE PHASE */
- int error = SELECT_OK;
-
- while(s->keepon) {
- ssize_t gotbytes;
- char byte;
-
- /* Read one byte at a time to avoid a race condition. Wait at most one
- second before looping to ensure continuous pgrsUpdates. */
- result = Curl_read(data, tunnelsocket, &byte, 1, &gotbytes);
- if(result == CURLE_AGAIN)
- /* socket buffer drained, return */
- return CURLE_OK;
- if(Curl_pgrsUpdate(data))
- return CURLE_ABORTED_BY_CALLBACK;
+ if(ts->keepon == KEEPON_IGNORE) {
+ /* This means we are currently ignoring a response-body */
- if(result) {
- s->keepon = KEEPON_DONE;
+ if(ts->cl) {
+ /* A Content-Length based body: simply count down the counter
+ and make sure to break out of the loop when we're done! */
+ ts->cl--;
+ if(ts->cl <= 0) {
+ ts->keepon = KEEPON_DONE;
break;
}
- else if(gotbytes <= 0) {
- if(data->set.proxyauth && data->state.authproxy.avail &&
- data->state.aptr.proxyuserpwd) {
- /* proxy auth was requested and there was proxy auth available,
- then deem this as "mere" proxy disconnect */
- conn->bits.proxy_connect_closed = TRUE;
- infof(data, "Proxy CONNECT connection closed");
- }
- else {
- error = SELECT_ERROR;
- failf(data, "Proxy CONNECT aborted");
- }
- s->keepon = KEEPON_DONE;
- break;
- }
-
- if(s->keepon == KEEPON_IGNORE) {
- /* This means we are currently ignoring a response-body */
-
- if(s->cl) {
- /* A Content-Length based body: simply count down the counter
- and make sure to break out of the loop when we're done! */
- s->cl--;
- if(s->cl <= 0) {
- s->keepon = KEEPON_DONE;
- s->tunnel_state = TUNNEL_COMPLETE;
- break;
- }
- }
- else {
- /* chunked-encoded body, so we need to do the chunked dance
- properly to know when the end of the body is reached */
- CHUNKcode r;
- CURLcode extra;
- ssize_t tookcareof = 0;
-
- /* now parse the chunked piece of data so that we can
- properly tell when the stream ends */
- r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
- if(r == CHUNKE_STOP) {
- /* we're done reading chunks! */
- infof(data, "chunk reading DONE");
- s->keepon = KEEPON_DONE;
- /* we did the full CONNECT treatment, go COMPLETE */
- s->tunnel_state = TUNNEL_COMPLETE;
- }
- }
- continue;
- }
-
- if(Curl_dyn_addn(&s->rcvbuf, &byte, 1)) {
- failf(data, "CONNECT response too large");
- return CURLE_RECV_ERROR;
+ }
+ else {
+ /* chunked-encoded body, so we need to do the chunked dance
+ properly to know when the end of the body is reached */
+ CHUNKcode r;
+ CURLcode extra;
+ ssize_t tookcareof = 0;
+
+ /* now parse the chunked piece of data so that we can
+ properly tell when the stream ends */
+ r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE");
+ ts->keepon = KEEPON_DONE;
}
+ }
+ continue;
+ }
- /* if this is not the end of a header line then continue */
- if(byte != 0x0a)
- continue;
-
- s->headerlines++;
- linep = Curl_dyn_ptr(&s->rcvbuf);
- perline = Curl_dyn_len(&s->rcvbuf); /* amount of bytes in this line */
-
- /* output debug if that is requested */
- Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
+ if(Curl_dyn_addn(&ts->rcvbuf, &byte, 1)) {
+ failf(data, "CONNECT response too large");
+ return CURLE_RECV_ERROR;
+ }
- if(!data->set.suppress_connect_headers) {
- /* send the header to the callback */
- int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
- (data->set.include_header ? CLIENTWRITE_BODY : 0) |
- (s->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
+ /* if this is not the end of a header line then continue */
+ if(byte != 0x0a)
+ continue;
- result = Curl_client_write(data, writetype, linep, perline);
- if(result)
- return result;
- }
+ ts->headerlines++;
+ linep = Curl_dyn_ptr(&ts->rcvbuf);
+ perline = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
- data->info.header_size += (long)perline;
-
- /* Newlines are CRLF, so the CR is ignored as the line isn't
- really terminated until the LF comes. Treat a following CR
- as end-of-headers as well.*/
-
- if(('\r' == linep[0]) ||
- ('\n' == linep[0])) {
- /* end of response-headers from the proxy */
-
- if((407 == k->httpcode) && !data->state.authproblem) {
- /* If we get a 407 response code with content length
- when we have no auth problem, we must ignore the
- whole response-body */
- s->keepon = KEEPON_IGNORE;
-
- if(s->cl) {
- infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
- " bytes of response-body", s->cl);
- }
- else if(s->chunked_encoding) {
- CHUNKcode r;
- CURLcode extra;
-
- infof(data, "Ignore chunked response-body");
-
- /* We set ignorebody true here since the chunked decoder
- function will acknowledge that. Pay attention so that this is
- cleared again when this function returns! */
- k->ignorebody = TRUE;
-
- if(linep[1] == '\n')
- /* this can only be a LF if the letter at index 0 was a CR */
- linep++;
-
- /* now parse the chunked piece of data so that we can properly
- tell when the stream ends */
- r = Curl_httpchunk_read(data, linep + 1, 1, &gotbytes,
- &extra);
- if(r == CHUNKE_STOP) {
- /* we're done reading chunks! */
- infof(data, "chunk reading DONE");
- s->keepon = KEEPON_DONE;
- /* we did the full CONNECT treatment, go to COMPLETE */
- s->tunnel_state = TUNNEL_COMPLETE;
- }
- }
- else {
- /* without content-length or chunked encoding, we
- can't keep the connection alive since the close is
- the end signal so we bail out at once instead */
- s->keepon = KEEPON_DONE;
- }
- }
- else
- s->keepon = KEEPON_DONE;
+ /* output debug if that is requested */
+ Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
- if(s->keepon == KEEPON_DONE && !s->cl)
- /* we did the full CONNECT treatment, go to COMPLETE */
- s->tunnel_state = TUNNEL_COMPLETE;
+ if(!data->set.suppress_connect_headers) {
+ /* send the header to the callback */
+ int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
+ (data->set.include_header ? CLIENTWRITE_BODY : 0) |
+ (ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
- DEBUGASSERT(s->keepon == KEEPON_IGNORE || s->keepon == KEEPON_DONE);
- continue;
- }
+ result = Curl_client_write(data, writetype, linep, perline);
+ if(result)
+ return result;
+ }
- if((checkprefix("WWW-Authenticate:", linep) &&
- (401 == k->httpcode)) ||
- (checkprefix("Proxy-authenticate:", linep) &&
- (407 == k->httpcode))) {
+ data->info.header_size += (long)perline;
- bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
- char *auth = Curl_copy_header_value(linep);
- if(!auth)
- return CURLE_OUT_OF_MEMORY;
+ /* Newlines are CRLF, so the CR is ignored as the line isn't
+ really terminated until the LF comes. Treat a following CR
+ as end-of-headers as well.*/
- result = Curl_http_input_auth(data, proxy, auth);
+ if(('\r' == linep[0]) ||
+ ('\n' == linep[0])) {
+ /* end of response-headers from the proxy */
- free(auth);
+ if((407 == k->httpcode) && !data->state.authproblem) {
+ /* If we get a 407 response code with content length
+ when we have no auth problem, we must ignore the
+ whole response-body */
+ ts->keepon = KEEPON_IGNORE;
- if(result)
- return result;
+ if(ts->cl) {
+ infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
+ " bytes of response-body", ts->cl);
}
- else if(checkprefix("Content-Length:", linep)) {
- if(k->httpcode/100 == 2) {
- /* A client MUST ignore any Content-Length or Transfer-Encoding
- header fields received in a successful response to CONNECT.
- "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
- infof(data, "Ignoring Content-Length in CONNECT %03d response",
- k->httpcode);
- }
- else {
- (void)curlx_strtoofft(linep +
- strlen("Content-Length:"), NULL, 10, &s->cl);
+ else if(ts->chunked_encoding) {
+ CHUNKcode r;
+ CURLcode extra;
+
+ infof(data, "Ignore chunked response-body");
+
+ /* We set ignorebody true here since the chunked decoder
+ function will acknowledge that. Pay attention so that this is
+ cleared again when this function returns! */
+ k->ignorebody = TRUE;
+
+ if(linep[1] == '\n')
+ /* this can only be a LF if the letter at index 0 was a CR */
+ linep++;
+
+ /* now parse the chunked piece of data so that we can properly
+ tell when the stream ends */
+ r = Curl_httpchunk_read(data, linep + 1, 1, &gotbytes,
+ &extra);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE");
+ ts->keepon = KEEPON_DONE;
}
}
- else if(Curl_compareheader(linep,
- STRCONST("Connection:"), STRCONST("close")))
- s->close_connection = TRUE;
- else if(checkprefix("Transfer-Encoding:", linep)) {
- if(k->httpcode/100 == 2) {
- /* A client MUST ignore any Content-Length or Transfer-Encoding
- header fields received in a successful response to CONNECT.
- "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
- infof(data, "Ignoring Transfer-Encoding in "
- "CONNECT %03d response", k->httpcode);
- }
- else if(Curl_compareheader(linep,
- STRCONST("Transfer-Encoding:"),
- STRCONST("chunked"))) {
- infof(data, "CONNECT responded chunked");
- s->chunked_encoding = TRUE;
- /* init our chunky engine */
- Curl_httpchunk_init(data);
- }
+ else {
+ /* without content-length or chunked encoding, we
+ can't keep the connection alive since the close is
+ the end signal so we bail out at once instead */
+ DEBUGF(infof(data, "CONNECT: no content-length or chunked"));
+ ts->keepon = KEEPON_DONE;
}
- else if(Curl_compareheader(linep,
- STRCONST("Proxy-Connection:"),
- STRCONST("close")))
- s->close_connection = TRUE;
- else if(2 == sscanf(linep, "HTTP/1.%d %d",
- &subversion,
- &k->httpcode)) {
- /* store the HTTP code from the proxy */
- data->info.httpproxycode = k->httpcode;
- }
-
- Curl_dyn_reset(&s->rcvbuf);
- } /* while there's buffer left and loop is requested */
-
- if(Curl_pgrsUpdate(data))
- return CURLE_ABORTED_BY_CALLBACK;
-
- if(error)
- return CURLE_RECV_ERROR;
-
- if(data->info.httpproxycode/100 != 2) {
- /* Deal with the possibly already received authenticate
- headers. 'newurl' is set to a new URL if we must loop. */
- result = Curl_http_auth_act(data);
- if(result)
- return result;
-
- if(conn->bits.close)
- /* the connection has been marked for closure, most likely in the
- Curl_http_auth_act() function and thus we can kill it at once
- below */
- s->close_connection = TRUE;
}
-
- if(s->close_connection && data->req.newurl) {
- /* Connection closed by server. Don't use it anymore */
- Curl_closesocket(data, conn, conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
- break;
+ else {
+ ts->keepon = KEEPON_DONE;
}
- } /* END READING RESPONSE PHASE */
- /* If we are supposed to continue and request a new URL, which basically
- * means the HTTP authentication is still going on so if the tunnel
- * is complete we start over in INIT state */
- if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
- connect_init(data, TRUE); /* reinit */
+ DEBUGASSERT(ts->keepon == KEEPON_IGNORE
+ || ts->keepon == KEEPON_DONE);
+ continue;
}
- } while(data->req.newurl);
-
- if(data->info.httpproxycode/100 != 2) {
- if(s->close_connection && data->req.newurl) {
- conn->bits.proxy_connect_closed = TRUE;
- infof(data, "Connect me again please");
- Curl_connect_done(data);
- }
- else {
- free(data->req.newurl);
- data->req.newurl = NULL;
- /* failure, close this connection to avoid re-use */
- streamclose(conn, "proxy CONNECT failure");
- }
+ result = on_resp_header(data, ts, linep);
+ if(result)
+ return result;
- /* to back to init state */
- s->tunnel_state = TUNNEL_INIT;
+ Curl_dyn_reset(&ts->rcvbuf);
+ } /* while there's buffer left and loop is requested */
- if(conn->bits.proxy_connect_closed)
- /* this is not an error, just part of the connection negotiation */
- return CURLE_OK;
- Curl_dyn_free(&s->rcvbuf);
- failf(data, "Received HTTP code %d from proxy after CONNECT",
- data->req.httpcode);
- return CURLE_RECV_ERROR;
+ if(error)
+ result = CURLE_RECV_ERROR;
+ *done = (ts->keepon == KEEPON_DONE);
+ if(!result && *done && data->info.httpproxycode/100 != 2) {
+ /* Deal with the possibly already received authenticate
+ headers. 'newurl' is set to a new URL if we must loop. */
+ result = Curl_http_auth_act(data);
}
-
- s->tunnel_state = TUNNEL_COMPLETE;
-
- /* If a proxy-authorization header was used for the proxy, then we should
- make sure that it isn't accidentally used for the document request
- after we've connected. So let's free and clear it here. */
- Curl_safefree(data->state.aptr.proxyuserpwd);
- data->state.aptr.proxyuserpwd = NULL;
-
- data->state.authproxy.done = TRUE;
- data->state.authproxy.multipass = FALSE;
-
- infof(data, "Proxy replied %d to CONNECT request",
- data->info.httpproxycode);
- data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
- conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
- document request */
- Curl_dyn_free(&s->rcvbuf);
- return CURLE_OK;
+ return result;
}
-#else
+
+#else /* USE_HYPER */
/* The Hyper version of CONNECT */
-static CURLcode CONNECT(struct Curl_easy *data,
- int sockindex,
- const char *hostname,
- int remote_port)
+static CURLcode start_CONNECT(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts)
{
- struct connectdata *conn = data->conn;
struct hyptransfer *h = &data->hyp;
- curl_socket_t tunnelsocket = conn->sock[sockindex];
- struct http_connect_state *s = conn->connect_state;
- CURLcode result = CURLE_OUT_OF_MEMORY;
+ curl_socket_t tunnelsocket = conn->sock[ts->sockindex];
hyper_io *io = NULL;
hyper_request *req = NULL;
hyper_headers *headers = NULL;
hyper_clientconn_options *options = NULL;
hyper_task *handshake = NULL;
hyper_task *task = NULL; /* for the handshake */
- hyper_task *sendtask = NULL; /* for the send */
hyper_clientconn *client = NULL;
- hyper_error *hypererr = NULL;
+ hyper_task *sendtask = NULL; /* for the send */
char *hostheader = NULL; /* for CONNECT */
char *host = NULL; /* Host: */
+ CURLcode result = CURLE_OUT_OF_MEMORY;
- if(Curl_connect_complete(conn))
- return CURLE_OK; /* CONNECT is already completed */
+ io = hyper_io_new();
+ if(!io) {
+ failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ /* tell Hyper how to read/write network data */
+ hyper_io_set_userdata(io, data);
+ hyper_io_set_read(io, Curl_hyper_recv);
+ hyper_io_set_write(io, Curl_hyper_send);
+ conn->sockfd = tunnelsocket;
+
+ data->state.hconnect = TRUE;
+
+ /* create an executor to poll futures */
+ if(!h->exec) {
+ h->exec = hyper_executor_new();
+ if(!h->exec) {
+ failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ }
- conn->bits.proxy_connect_closed = FALSE;
+ options = hyper_clientconn_options_new();
+ hyper_clientconn_options_set_preserve_header_case(options, 1);
+ hyper_clientconn_options_set_preserve_header_order(options, 1);
- do {
- switch(s->tunnel_state) {
- case TUNNEL_INIT:
- /* BEGIN CONNECT PHASE */
- io = hyper_io_new();
- if(!io) {
- failf(data, "Couldn't create hyper IO");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- /* tell Hyper how to read/write network data */
- hyper_io_set_userdata(io, data);
- hyper_io_set_read(io, Curl_hyper_recv);
- hyper_io_set_write(io, Curl_hyper_send);
- conn->sockfd = tunnelsocket;
-
- data->state.hconnect = TRUE;
-
- /* create an executor to poll futures */
- if(!h->exec) {
- h->exec = hyper_executor_new();
- if(!h->exec) {
- failf(data, "Couldn't create hyper executor");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- }
+ if(!options) {
+ failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- options = hyper_clientconn_options_new();
- hyper_clientconn_options_set_preserve_header_case(options, 1);
- hyper_clientconn_options_set_preserve_header_order(options, 1);
+ hyper_clientconn_options_exec(options, h->exec);
- if(!options) {
- failf(data, "Couldn't create hyper client options");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ /* "Both the `io` and the `options` are consumed in this function
+ call" */
+ handshake = hyper_clientconn_handshake(io, options);
+ if(!handshake) {
+ failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ io = NULL;
+ options = NULL;
- hyper_clientconn_options_exec(options, h->exec);
+ if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+ failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ handshake = NULL; /* ownership passed on */
- /* "Both the `io` and the `options` are consumed in this function
- call" */
- handshake = hyper_clientconn_handshake(io, options);
- if(!handshake) {
- failf(data, "Couldn't create hyper client handshake");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- io = NULL;
- options = NULL;
+ task = hyper_executor_poll(h->exec);
+ if(!task) {
+ failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
- failf(data, "Couldn't hyper_executor_push the handshake");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- handshake = NULL; /* ownership passed on */
+ client = hyper_task_value(task);
+ hyper_task_free(task);
+ req = hyper_request_new();
+ if(!req) {
+ failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
+ strlen("CONNECT"))) {
+ failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- task = hyper_executor_poll(h->exec);
- if(!task) {
- failf(data, "Couldn't hyper_executor_poll the handshake");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
+ ts->hostname, ts->remote_port);
- client = hyper_task_value(task);
- hyper_task_free(task);
- req = hyper_request_new();
- if(!req) {
- failf(data, "Couldn't hyper_request_new");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
- strlen("CONNECT"))) {
- failf(data, "error setting method");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ Curl_safefree(data->req.newurl);
- infof(data, "Establish HTTP proxy tunnel to %s:%d",
- hostname, remote_port);
+ result = CONNECT_host(data, conn, ts->hostname, ts->remote_port,
+ &hostheader, &host);
+ if(result)
+ goto error;
- /* This only happens if we've looped here due to authentication
- reasons, and we don't really use the newly cloned URL here
- then. Just free() it. */
- Curl_safefree(data->req.newurl);
+ if(hyper_request_set_uri(req, (uint8_t *)hostheader,
+ strlen(hostheader))) {
+ failf(data, "error setting path");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(data->set.verbose) {
+ char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader);
+ if(!se) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
+ free(se);
+ }
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+ hostheader, TRUE);
+ if(result)
+ goto error;
+ Curl_safefree(hostheader);
+
+ /* default is 1.1 */
+ if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
+ (HYPERE_OK != hyper_request_set_version(req,
+ HYPER_HTTP_VERSION_1_0))) {
+ failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- result = CONNECT_host(data, conn, hostname, remote_port,
- &hostheader, &host);
- if(result)
- goto error;
+ headers = hyper_request_headers(req);
+ if(!headers) {
+ failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(host) {
+ result = Curl_hyper_header(data, headers, host);
+ if(result)
+ goto error;
+ Curl_safefree(host);
+ }
- if(hyper_request_set_uri(req, (uint8_t *)hostheader,
- strlen(hostheader))) {
- failf(data, "error setting path");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- if(data->set.verbose) {
- char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader);
- if(!se) {
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
- free(se);
- }
- /* Setup the proxy-authorization header, if any */
- result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
- hostheader, TRUE);
- if(result)
- goto error;
- Curl_safefree(hostheader);
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
- /* default is 1.1 */
- if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
- (HYPERE_OK != hyper_request_set_version(req,
- HYPER_HTTP_VERSION_1_0))) {
- failf(data, "error setting HTTP version");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
+ data->set.str[STRING_USERAGENT]) {
+ struct dynbuf ua;
+ Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
+ result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
+ data->set.str[STRING_USERAGENT]);
+ if(result)
+ goto error;
+ result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
+ if(result)
+ goto error;
+ Curl_dyn_free(&ua);
+ }
+
+ if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
+ result = Curl_hyper_header(data, headers,
+ "Proxy-Connection: Keep-Alive");
+ if(result)
+ goto error;
+ }
+
+ result = Curl_add_custom_headers(data, TRUE, headers);
+ if(result)
+ goto error;
+
+ sendtask = hyper_clientconn_send(client, req);
+ if(!sendtask) {
+ failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+
+ if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+ failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
- headers = hyper_request_headers(req);
- if(!headers) {
- failf(data, "hyper_request_headers");
+error:
+ free(host);
+ free(hostheader);
+ if(io)
+ hyper_io_free(io);
+ if(options)
+ hyper_clientconn_options_free(options);
+ if(handshake)
+ hyper_task_free(handshake);
+ if(client)
+ hyper_clientconn_free(client);
+ return result;
+}
+
+static CURLcode send_CONNECT(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts,
+ bool *done)
+{
+ struct hyptransfer *h = &data->hyp;
+ hyper_task *task = NULL;
+ hyper_error *hypererr = NULL;
+ CURLcode result = CURLE_OK;
+
+ (void)ts;
+ (void)conn;
+ do {
+ task = hyper_executor_poll(h->exec);
+ if(task) {
+ bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+ if(error)
+ hypererr = hyper_task_value(task);
+ hyper_task_free(task);
+ if(error) {
+ /* this could probably use a better error code? */
result = CURLE_OUT_OF_MEMORY;
goto error;
}
- if(host) {
- result = Curl_hyper_header(data, headers, host);
- if(result)
- goto error;
- Curl_safefree(host);
- }
+ }
+ } while(task);
+error:
+ *done = (result == CURLE_OK);
+ if(hypererr) {
+ uint8_t errbuf[256];
+ size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+ failf(data, "Hyper: %.*s", (int)errlen, errbuf);
+ hyper_error_free(hypererr);
+ }
+ return result;
+}
- if(data->state.aptr.proxyuserpwd) {
- result = Curl_hyper_header(data, headers,
- data->state.aptr.proxyuserpwd);
- if(result)
- goto error;
- }
+static CURLcode recv_CONNECT_resp(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct tunnel_state *ts,
+ bool *done)
+{
+ struct hyptransfer *h = &data->hyp;
+ CURLcode result;
+ int didwhat;
+
+ (void)ts;
+ *done = FALSE;
+ result = Curl_hyper_stream(data, conn, &didwhat, done,
+ CURL_CSELECT_IN | CURL_CSELECT_OUT);
+ if(result || !*done)
+ return result;
+ if(h->exec) {
+ hyper_executor_free(h->exec);
+ h->exec = NULL;
+ }
+ if(h->read_waker) {
+ hyper_waker_free(h->read_waker);
+ h->read_waker = NULL;
+ }
+ if(h->write_waker) {
+ hyper_waker_free(h->write_waker);
+ h->write_waker = NULL;
+ }
+ return result;
+}
- if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
- data->set.str[STRING_USERAGENT]) {
- struct dynbuf ua;
- Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
- result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
- data->set.str[STRING_USERAGENT]);
- if(result)
- goto error;
- result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
- if(result)
- goto error;
- Curl_dyn_free(&ua);
- }
+#endif /* USE_HYPER */
- if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
- result = Curl_hyper_header(data, headers,
- "Proxy-Connection: Keep-Alive");
- if(result)
- goto error;
- }
+static CURLcode CONNECT(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct tunnel_state *ts)
+{
+ struct connectdata *conn = cf->conn;
+ CURLcode result;
+ bool done;
+
+ if(tunnel_is_established(ts))
+ return CURLE_OK;
+ if(tunnel_is_failed(ts))
+ return CURLE_RECV_ERROR; /* Need a cfilter close and new bootstrap */
+
+ do {
+ timediff_t check;
- result = Curl_add_custom_headers(data, TRUE, headers);
+ check = Curl_timeleft(data, NULL, TRUE);
+ if(check <= 0) {
+ failf(data, "Proxy CONNECT aborted due to timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
+ }
+
+ switch(ts->tunnel_state) {
+ case TUNNEL_INIT:
+ /* Prepare the CONNECT request and make a first attempt to send. */
+ result = start_CONNECT(data, cf->conn, ts);
if(result)
- goto error;
+ goto out;
+ tunnel_go_state(cf, ts, TUNNEL_CONNECT, data);
+ /* FALLTHROUGH */
- sendtask = hyper_clientconn_send(client, req);
- if(!sendtask) {
- failf(data, "hyper_clientconn_send");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ case TUNNEL_CONNECT:
+ /* see that the request is completely sent */
+ result = send_CONNECT(data, cf->conn, ts, &done);
+ if(result || !done)
+ goto out;
+ tunnel_go_state(cf, ts, TUNNEL_RECEIVE, data);
+ /* FALLTHROUGH */
- if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
- failf(data, "Couldn't hyper_executor_push the send");
- result = CURLE_OUT_OF_MEMORY;
- goto error;
+ case TUNNEL_RECEIVE:
+ /* read what is there */
+ result = recv_CONNECT_resp(data, cf->conn, ts, &done);
+ if(Curl_pgrsUpdate(data)) {
+ result = CURLE_ABORTED_BY_CALLBACK;
+ goto out;
}
+ /* error or not complete yet. return for more multi-multi */
+ if(result || !done)
+ goto out;
+ /* got it */
+ tunnel_go_state(cf, ts, TUNNEL_RESPONSE, data);
+ /* FALLTHROUGH */
- hyper_clientconn_free(client);
-
- do {
- task = hyper_executor_poll(h->exec);
- if(task) {
- bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
- if(error)
- hypererr = hyper_task_value(task);
- hyper_task_free(task);
- if(error) {
- /* this could probably use a better error code? */
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
+ case TUNNEL_RESPONSE:
+ if(data->req.newurl) {
+ /* not the "final" response, we need to do a follow up request.
+ * If the other side indicated a connection close, or if someone
+ * else told us to close this connection, do so now. */
+ if(ts->close_connection || conn->bits.close) {
+ /* Close the filter chain and trigger connect, non-blocking
+ * again, so the process is ongoing. This will
+ * a) the close resets our tunnel state
+ * b) the connect makes sure that there will be a socket
+ * to select on again.
+ * We return and expect to be called again. */
+ infof(data, "Connect me again please");
+ Curl_conn_close(data, cf->sockindex);
+ result = cf->next->cft->connect(cf->next, data, FALSE, &done);
+ goto out;
}
- } while(task);
- s->tunnel_state = TUNNEL_CONNECT;
- /* FALLTHROUGH */
- case TUNNEL_CONNECT: {
- int didwhat;
- bool done = FALSE;
- result = Curl_hyper_stream(data, conn, &didwhat, &done,
- CURL_CSELECT_IN | CURL_CSELECT_OUT);
- if(result)
- goto error;
- if(!done)
- break;
- s->tunnel_state = TUNNEL_COMPLETE;
- if(h->exec) {
- hyper_executor_free(h->exec);
- h->exec = NULL;
+ /* staying on this connection, reset state */
+ tunnel_go_state(cf, ts, TUNNEL_INIT, data);
}
- if(h->read_waker) {
- hyper_waker_free(h->read_waker);
- h->read_waker = NULL;
- }
- if(h->write_waker) {
- hyper_waker_free(h->write_waker);
- h->write_waker = NULL;
- }
- }
- break;
-
- default:
break;
- }
- if(conn->bits.close && data->req.newurl) {
- /* Connection closed by server. Don't use it anymore */
- Curl_closesocket(data, conn, conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
+ default:
break;
}
- /* If we are supposed to continue and request a new URL, which basically
- * means the HTTP authentication is still going on so if the tunnel
- * is complete we start over in INIT state */
- if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
- infof(data, "CONNECT request done, loop to make another");
- connect_init(data, TRUE); /* reinit */
- }
} while(data->req.newurl);
+ DEBUGASSERT(ts->tunnel_state == TUNNEL_RESPONSE);
+ if(data->info.httpproxycode/100 != 2) {
+ /* a non-2xx response and we have no next url to try. */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ /* failure, close this connection to avoid re-use */
+ streamclose(conn, "proxy CONNECT failure");
+ tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
+ failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
+ return CURLE_RECV_ERROR;
+ }
+ /* 2xx response, SUCCESS! */
+ tunnel_go_state(cf, ts, TUNNEL_ESTABLISHED, data);
+ infof(data, "CONNECT tunnel established, response %d",
+ data->info.httpproxycode);
result = CURLE_OK;
- if(s->tunnel_state == TUNNEL_COMPLETE) {
- if(data->info.httpproxycode/100 != 2) {
- if(conn->bits.close && data->req.newurl) {
- conn->bits.proxy_connect_closed = TRUE;
- infof(data, "Connect me again please");
- Curl_connect_done(data);
- }
- else {
- free(data->req.newurl);
- data->req.newurl = NULL;
- /* failure, close this connection to avoid re-use */
- streamclose(conn, "proxy CONNECT failure");
- Curl_closesocket(data, conn, conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
- }
- /* to back to init state */
- s->tunnel_state = TUNNEL_INIT;
+out:
+ if(result)
+ tunnel_go_state(cf, ts, TUNNEL_FAILED, data);
+ return result;
+}
- if(!conn->bits.proxy_connect_closed) {
- failf(data, "Received HTTP code %d from proxy after CONNECT",
- data->req.httpcode);
- result = CURLE_RECV_ERROR;
- }
- }
+static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ CURLcode result;
+ struct tunnel_state *ts = cf->ctx;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
}
- error:
- free(host);
- free(hostheader);
- if(io)
- hyper_io_free(io);
- if(options)
- hyper_clientconn_options_free(options);
+ result = cf->next->cft->connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ return result;
- if(handshake)
- hyper_task_free(handshake);
+ /* TODO: can we do blocking? */
+ /* We want "seamless" operations through HTTP proxy tunnel */
- if(hypererr) {
- uint8_t errbuf[256];
- size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
- failf(data, "Hyper: %.*s", (int)errlen, errbuf);
- hyper_error_free(hypererr);
+ /* for the secondary socket (FTP), use the "connect to host"
+ * but ignore the "connect to port" (use the secondary port)
+ */
+ *done = FALSE;
+ if(!ts) {
+ result = tunnel_init(&ts, data, cf->conn, cf->sockindex);
+ if(result)
+ return result;
+ cf->ctx = ts;
+ }
+
+ result = CONNECT(cf, data, ts);
+ if(result)
+ goto out;
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+
+out:
+ *done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
+ if (*done) {
+ cf->connected = TRUE;
+ tunnel_free(cf, data);
}
return result;
}
-#endif
-void Curl_connect_free(struct Curl_easy *data)
+static void http_proxy_cf_get_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char **phost,
+ const char **pdisplay_host,
+ int *pport)
+{
+ (void)data;
+ if(!cf->connected) {
+ *phost = cf->conn->http_proxy.host.name;
+ *pdisplay_host = cf->conn->http_proxy.host.dispname;
+ *pport = (int)cf->conn->http_proxy.port;
+ }
+ else {
+ cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+ }
+}
+
+static int http_proxy_cf_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ struct tunnel_state *ts = cf->ctx;
+ struct connectdata *conn = cf->conn;
+ int fds;
+
+ DEBUGASSERT(conn);
+ fds = cf->next->cft->get_select_socks(cf->next, data, socks);
+ if(!fds && cf->next->connected && !cf->connected) {
+ /* If we are not connected, but the filter "below" is
+ * and not waiting on something, we are tunneling. */
+ socks[0] = conn->sock[cf->sockindex];
+ if(ts) {
+ /* when we've sent a CONNECT to a proxy, we should rather either
+ wait for the socket to become readable to be able to get the
+ response headers or if we're still sending the request, wait
+ for write. */
+ if(ts->http_proxy.sending == HTTPSEND_REQUEST)
+ return GETSOCK_WRITESOCK(0);
+ return GETSOCK_READSOCK(0);
+ }
+ return GETSOCK_WRITESOCK(0);
+ }
+ return fds;
+}
+
+static void http_proxy_cf_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ if(cf->ctx) {
+ tunnel_free(cf, data);
+ }
+}
+
+static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ http_proxy_cf_detach_data(cf, data);
+}
+
+static void http_proxy_cf_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
- struct http_connect_state *s = conn->connect_state;
- if(s) {
- free(s);
- conn->connect_state = NULL;
+ DEBUGASSERT(cf->next);
+ cf->connected = FALSE;
+ cf->next->cft->close(cf->next, data);
+ if(cf->ctx) {
+ tunnel_go_state(cf, cf->ctx, TUNNEL_INIT, data);
}
}
-/*
- * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
- * function will issue the necessary commands to get a seamless tunnel through
- * this proxy. After that, the socket can be used just as a normal socket.
- */
-CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
- int sockindex,
- const char *hostname,
- int remote_port)
+static const struct Curl_cftype cft_http_proxy = {
+ "HTTP-PROXY",
+ CF_TYPE_IP_CONNECT,
+ http_proxy_cf_destroy,
+ Curl_cf_def_setup,
+ http_proxy_cf_connect,
+ http_proxy_cf_close,
+ http_proxy_cf_get_host,
+ http_proxy_cf_get_select_socks,
+ Curl_cf_def_data_pending,
+ Curl_cf_def_send,
+ Curl_cf_def_recv,
+ Curl_cf_def_attach_data,
+ http_proxy_cf_detach_data,
+};
+
+CURLcode Curl_conn_http_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
{
+ struct Curl_cfilter *cf;
CURLcode result;
- struct connectdata *conn = data->conn;
- if(!conn->connect_state) {
- result = connect_init(data, FALSE);
- if(result)
- return result;
+
+ result = Curl_cf_create(&cf, &cft_http_proxy, NULL);
+ if(!result)
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+ return result;
+}
+
+
+static CURLcode send_haproxy_header(struct Curl_cfilter*cf,
+ struct Curl_easy *data)
+{
+ struct dynbuf req;
+ CURLcode result;
+ const char *tcp_version;
+ Curl_dyn_init(&req, DYN_HAXPROXY);
+
+#ifdef USE_UNIX_SOCKETS
+ if(cf->conn->unix_domain_socket)
+ /* the buffer is large enough to hold this! */
+ result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
+ else {
+#endif /* USE_UNIX_SOCKETS */
+ /* Emit the correct prefix for IPv6 */
+ tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
+
+ result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
+ tcp_version,
+ data->info.conn_local_ip,
+ data->info.conn_primary_ip,
+ data->info.conn_local_port,
+ data->info.conn_primary_port);
+
+#ifdef USE_UNIX_SOCKETS
}
- result = CONNECT(data, sockindex, hostname, remote_port);
+#endif /* USE_UNIX_SOCKETS */
- if(result || Curl_connect_complete(conn))
- Curl_connect_done(data);
+ if(!result)
+ result = Curl_buffer_send(&req, data, &data->info.request_size,
+ 0, FIRSTSOCKET);
+ return result;
+}
+
+static CURLcode haproxy_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ CURLcode result;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ result = cf->next->cft->connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ return result;
+ result = send_haproxy_header(cf, data);
+ *done = (!result);
+ cf->connected = *done;
return result;
}
-#else
-void Curl_connect_free(struct Curl_easy *data)
+static const struct Curl_cftype cft_haproxy = {
+ "HAPROXY",
+ 0,
+ Curl_cf_def_destroy_this,
+ Curl_cf_def_setup,
+ haproxy_cf_connect,
+ Curl_cf_def_close,
+ Curl_cf_def_get_host,
+ Curl_cf_def_get_select_socks,
+ Curl_cf_def_data_pending,
+ Curl_cf_def_send,
+ Curl_cf_def_recv,
+ Curl_cf_def_attach_data,
+ Curl_cf_def_detach_data,
+};
+
+CURLcode Curl_conn_haproxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
{
- (void)data;
+ struct Curl_cfilter *cf;
+ CURLcode result;
+
+ result = Curl_cf_create(&cf, &cft_haproxy, NULL);
+ if(!result)
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+ return result;
}
-#endif /* CURL_DISABLE_PROXY */
+#endif /* !CURL_DISABLE_PROXY &6 ! CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index 1e650ee..dfdc0e7 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -28,54 +28,18 @@
#include "urldata.h"
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
-/* ftp can use this as well */
-CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
- int tunnelsocket,
- const char *hostname, int remote_port);
/* Default proxy timeout in milliseconds */
#define PROXY_TIMEOUT (3600*1000)
-CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
+CURLcode Curl_conn_http_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
-bool Curl_connect_complete(struct connectdata *conn);
-bool Curl_connect_ongoing(struct connectdata *conn);
-int Curl_connect_getsock(struct connectdata *conn);
-void Curl_connect_done(struct Curl_easy *data);
+CURLcode Curl_conn_haproxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
-#else
-#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
-#define Curl_proxy_connect(x,y) CURLE_OK
-#define Curl_connect_complete(x) CURLE_OK
-#define Curl_connect_ongoing(x) FALSE
-#define Curl_connect_getsock(x) 0
-#define Curl_connect_done(x)
-#endif
-
-void Curl_connect_free(struct Curl_easy *data);
-
-/* struct for HTTP CONNECT state data */
-struct http_connect_state {
- struct HTTP http_proxy;
- struct HTTP *prot_save;
- struct dynbuf rcvbuf;
- struct dynbuf req;
- size_t nsend;
- size_t headerlines;
- enum keeponval {
- KEEPON_DONE,
- KEEPON_CONNECT,
- KEEPON_IGNORE
- } keepon;
- curl_off_t cl; /* size of content to read and ignore */
- enum {
- TUNNEL_INIT, /* init/default/no tunnel state */
- TUNNEL_CONNECT, /* CONNECT has been sent off */
- TUNNEL_COMPLETE, /* CONNECT response received completely */
- TUNNEL_EXIT
- } tunnel_state;
- BIT(chunked_encoding);
- BIT(close_connection);
-};
+#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
#endif /* HEADER_CURL_HTTP_PROXY_H */
diff --git a/Utilities/cmcurl/lib/idn.c b/Utilities/cmcurl/lib/idn.c
new file mode 100644
index 0000000..6255221
--- /dev/null
+++ b/Utilities/cmcurl/lib/idn.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+ /*
+ * IDN conversions
+ */
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "idn.h"
+#include "sendf.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+
+#if defined(WIN32) && defined(UNICODE)
+#define IDN2_LOOKUP(name, host, flags) \
+ idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
+#else
+#define IDN2_LOOKUP(name, host, flags) \
+ idn2_lookup_ul((const char *)name, (char **)host, flags)
+#endif
+#endif /* USE_LIBIDN2 */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef USE_WIN32_IDN
+/* using Windows kernel32 and normaliz libraries. */
+
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
+WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
+ const WCHAR *lpUnicodeCharStr,
+ int cchUnicodeChar,
+ WCHAR *lpASCIICharStr,
+ int cchASCIIChar);
+WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
+ const WCHAR *lpASCIICharStr,
+ int cchASCIIChar,
+ WCHAR *lpUnicodeCharStr,
+ int cchUnicodeChar);
+#endif
+
+#define IDN_MAX_LENGTH 255
+
+bool Curl_win32_idn_to_ascii(const char *in, char **out)
+{
+ bool success = FALSE;
+
+ wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
+ if(in_w) {
+ wchar_t punycode[IDN_MAX_LENGTH];
+ int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
+ curlx_unicodefree(in_w);
+ if(chars) {
+ char *mstr = curlx_convert_wchar_to_UTF8(punycode);
+ if(mstr) {
+ *out = strdup(mstr);
+ curlx_unicodefree(mstr);
+ if(*out)
+ success = TRUE;
+ }
+ }
+ }
+
+ return success;
+}
+
+#endif /* USE_WIN32_IDN */
+
+/*
+ * Helpers for IDNA conversions.
+ */
+bool Curl_is_ASCII_name(const char *hostname)
+{
+ /* get an UNSIGNED local version of the pointer */
+ const unsigned char *ch = (const unsigned char *)hostname;
+
+ if(!hostname) /* bad input, consider it ASCII! */
+ return TRUE;
+
+ while(*ch) {
+ if(*ch++ & 0x80)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifdef USE_IDN
+/*
+ * Curl_idn_decode() returns an allocated IDN decoded string if it was
+ * possible. NULL on error.
+ */
+static char *Curl_idn_decode(const char *input)
+{
+ char *decoded = NULL;
+#ifdef USE_LIBIDN2
+ if(idn2_check_version(IDN2_VERSION)) {
+ int flags = IDN2_NFC_INPUT
+#if IDN2_VERSION_NUMBER >= 0x00140000
+ /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
+ IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
+ processing. */
+ | IDN2_NONTRANSITIONAL
+#endif
+ ;
+ int rc = IDN2_LOOKUP(input, &decoded, flags);
+ if(rc != IDN2_OK)
+ /* fallback to TR46 Transitional mode for better IDNA2003
+ compatibility */
+ rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL);
+ if(rc != IDN2_OK)
+ decoded = NULL;
+ }
+#elif defined(USE_WIN32_IDN)
+ if(!Curl_win32_idn_to_ascii(input, &decoded))
+ decoded = NULL;
+#endif
+ return decoded;
+}
+
+/*
+ * Frees data allocated by idnconvert_hostname()
+ */
+void Curl_free_idnconverted_hostname(struct hostname *host)
+{
+#if defined(USE_LIBIDN2)
+ if(host->encalloc) {
+ idn2_free(host->encalloc); /* must be freed with idn2_free() since this was
+ allocated by libidn */
+ host->encalloc = NULL;
+ }
+#elif defined(USE_WIN32_IDN)
+ free(host->encalloc); /* must be freed with free() since this was
+ allocated by Curl_win32_idn_to_ascii */
+ host->encalloc = NULL;
+#else
+ (void)host;
+#endif
+}
+
+#endif /* USE_IDN */
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+CURLcode Curl_idnconvert_hostname(struct hostname *host)
+{
+ /* set the name we use to display the host name */
+ host->dispname = host->name;
+
+#ifdef USE_IDN
+ /* Check name for non-ASCII and convert hostname if we can */
+ if(!Curl_is_ASCII_name(host->name)) {
+ char *decoded = Curl_idn_decode(host->name);
+ if(decoded) {
+ /* successful */
+ host->encalloc = decoded;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ else
+ return CURLE_URL_MALFORMAT;
+ }
+#endif
+ return CURLE_OK;
+}
+
diff --git a/Utilities/cmcurl/lib/idn.h b/Utilities/cmcurl/lib/idn.h
new file mode 100644
index 0000000..2d04efc
--- /dev/null
+++ b/Utilities/cmcurl/lib/idn.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_IDN_H
+#define HEADER_CURL_IDN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef USE_WIN32_IDN
+bool Curl_win32_idn_to_ascii(const char *in, char **out);
+#endif /* USE_WIN32_IDN */
+bool Curl_is_ASCII_name(const char *hostname);
+CURLcode Curl_idnconvert_hostname(struct hostname *host);
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+#define USE_IDN
+void Curl_free_idnconverted_hostname(struct hostname *host);
+#else
+#define Curl_free_idnconverted_hostname(x)
+#endif
+#endif /* HEADER_CURL_IDN_H */
diff --git a/Utilities/cmcurl/lib/idn_win32.c b/Utilities/cmcurl/lib/idn_win32.c
deleted file mode 100644
index 2433d92..0000000
--- a/Utilities/cmcurl/lib/idn_win32.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
- /*
- * IDN conversions using Windows kernel32 and normaliz libraries.
- */
-
-#include "curl_setup.h"
-
-#ifdef USE_WIN32_IDN
-
-#include "curl_multibyte.h"
-#include "curl_memory.h"
-#include "warnless.h"
-
- /* The last #include file should be: */
-#include "memdebug.h"
-
-#ifdef WANT_IDN_PROTOTYPES
-# if defined(_SAL_VERSION)
-WINNORMALIZEAPI int WINAPI
-IdnToAscii(_In_ DWORD dwFlags,
- _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr,
- _In_ int cchUnicodeChar,
- _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr,
- _In_ int cchASCIIChar);
-WINNORMALIZEAPI int WINAPI
-IdnToUnicode(_In_ DWORD dwFlags,
- _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr,
- _In_ int cchASCIIChar,
- _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr,
- _In_ int cchUnicodeChar);
-# else
-WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
- const WCHAR *lpUnicodeCharStr,
- int cchUnicodeChar,
- WCHAR *lpASCIICharStr,
- int cchASCIIChar);
-WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
- const WCHAR *lpASCIICharStr,
- int cchASCIIChar,
- WCHAR *lpUnicodeCharStr,
- int cchUnicodeChar);
-# endif
-#endif
-
-#define IDN_MAX_LENGTH 255
-
-bool Curl_win32_idn_to_ascii(const char *in, char **out);
-bool Curl_win32_ascii_to_idn(const char *in, char **out);
-
-bool Curl_win32_idn_to_ascii(const char *in, char **out)
-{
- bool success = FALSE;
-
- wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
- if(in_w) {
- wchar_t punycode[IDN_MAX_LENGTH];
- int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
- curlx_unicodefree(in_w);
- if(chars) {
- char *mstr = curlx_convert_wchar_to_UTF8(punycode);
- if(mstr) {
- *out = strdup(mstr);
- curlx_unicodefree(mstr);
- if(*out)
- success = TRUE;
- }
- }
- }
-
- return success;
-}
-
-bool Curl_win32_ascii_to_idn(const char *in, char **out)
-{
- bool success = FALSE;
-
- wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
- if(in_w) {
- size_t in_len = wcslen(in_w) + 1;
- wchar_t unicode[IDN_MAX_LENGTH];
- int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
- unicode, IDN_MAX_LENGTH);
- curlx_unicodefree(in_w);
- if(chars) {
- char *mstr = curlx_convert_wchar_to_UTF8(unicode);
- if(mstr) {
- *out = strdup(mstr);
- curlx_unicodefree(mstr);
- if(*out)
- success = TRUE;
- }
- }
- }
-
- return success;
-}
-
-#endif /* USE_WIN32_IDN */
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index ffa08bf..bd4c6f2 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -56,11 +56,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -75,11 +70,11 @@
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "select.h"
#include "multiif.h"
#include "url.h"
-#include "strcase.h"
#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
@@ -479,9 +474,15 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
{
/* Start the SSL connection */
struct imap_conn *imapc = &conn->proto.imapc;
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &imapc->ssldone);
+ CURLcode result;
+ if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
+ result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+ if(result)
+ goto out;
+ }
+
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &imapc->ssldone);
if(!result) {
if(imapc->state != IMAP_UPGRADETLS)
state(data, IMAP_UPGRADETLS);
@@ -491,7 +492,7 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
result = imap_perform_capability(data, conn);
}
}
-
+out:
return result;
}
@@ -776,7 +777,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
/* Add external headers and mime version. */
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
- result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+ result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
NULL, MIMESTRATEGY_MAIL);
if(!result)
@@ -951,7 +952,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
line += wordlen;
}
}
- else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ else if(data->set.use_ssl && !Curl_conn_is_ssl(data, FIRSTSOCKET)) {
/* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */
@@ -1385,8 +1386,7 @@ static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
struct imap_conn *imapc = &conn->proto.imapc;
if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &imapc->ssldone);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &imapc->ssldone);
if(result || !imapc->ssldone)
return result;
}
@@ -1561,7 +1561,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
DEBUGF(infof(data, "DO phase starts"));
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* Requested no body means no transfer */
imap->transfer = PPTRANSFER_INFO;
}
@@ -1603,7 +1603,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
/* Run the state-machine */
result = imap_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(conn, FIRSTSOCKET);
if(*dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 1c993c1..08a6825 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -41,6 +41,9 @@
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
#include "urldata.h"
#include "curl_base64.h"
@@ -451,14 +454,14 @@ static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
saying whether an error occurred or CURLE_OK if |len| was read. */
static CURLcode
-socket_read(curl_socket_t fd, void *to, size_t len)
+socket_read(struct Curl_easy *data, curl_socket_t fd, void *to, size_t len)
{
char *to_p = to;
CURLcode result;
ssize_t nread = 0;
while(len > 0) {
- result = Curl_read_plain(fd, to_p, len, &nread);
+ result = Curl_read_plain(data, fd, to_p, len, &nread);
if(!result) {
len -= nread;
to_p += nread;
@@ -499,15 +502,15 @@ socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
return CURLE_OK;
}
-static CURLcode read_data(struct connectdata *conn,
- curl_socket_t fd,
+static CURLcode read_data(struct Curl_easy *data, curl_socket_t fd,
struct krb5buffer *buf)
{
+ struct connectdata *conn = data->conn;
int len;
CURLcode result;
int nread;
- result = socket_read(fd, &len, sizeof(len));
+ result = socket_read(data, fd, &len, sizeof(len));
if(result)
return result;
@@ -522,7 +525,7 @@ static CURLcode read_data(struct connectdata *conn,
if(!len || !buf->data)
return CURLE_OUT_OF_MEMORY;
- result = socket_read(fd, buf->data, len);
+ result = socket_read(data, fd, buf->data, len);
if(result)
return result;
nread = conn->mech->decode(conn->app_data, buf->data, len,
@@ -557,7 +560,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
/* Handle clear text response. */
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
- return sread(fd, buffer, len);
+ return Curl_recv_plain(data, sockindex, buffer, len, err);
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
@@ -570,7 +573,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
buffer += bytes_read;
while(len > 0) {
- if(read_data(conn, fd, &conn->in_buffer))
+ if(read_data(data, fd, &conn->in_buffer))
return -1;
if(conn->in_buffer.size == 0) {
if(bytes_read > 0)
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index b073349..92006d6 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -565,8 +565,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) name,
- name_len);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, name, name_len);
if(result) {
FREE_ON_WINLDAP(name);
ldap_memfree(dn);
@@ -622,8 +621,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- (char *) attr, attr_len);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, attr, attr_len);
if(result) {
ldap_value_free_len(vals);
FREE_ON_WINLDAP(attr);
@@ -648,7 +646,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
dlsize += attr_len + 3;
if((attr_len > 7) &&
- (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
+ (strcmp(";binary", attr + (attr_len - 7)) == 0)) {
/* Binary attribute, encode to base64. */
result = Curl_base64_encode(vals[i]->bv_val, vals[i]->bv_len,
&val_b64, &val_b64_sz);
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index e976fe7..c13b080 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -26,10 +26,11 @@
#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#include <string.h>
+
#include "curl_md4.h"
#include "warnless.h"
-
#ifdef USE_OPENSSL
#include <openssl/opensslconf.h>
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) && \
@@ -53,21 +54,44 @@
#else
#include <mbedtls/config.h>
#endif
-
#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
#define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
#endif
#endif /* USE_MBEDTLS */
#if defined(USE_GNUTLS)
-
#include <nettle/md4.h>
+/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
+#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
+#include <wolfssl/openssl/md4.h>
+#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
+#include <openssl/md4.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+ defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+#define AN_APPLE_OS
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C))
+#include <mbedtls/md4.h>
+#endif
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
#include "curl_memory.h"
-
-/* The last #include file should be: */
#include "memdebug.h"
+
+#if defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
+
+#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
+
+#elif defined(USE_GNUTLS)
+
typedef struct md4_ctx MD4_CTX;
static void MD4_Init(MD4_CTX *ctx)
@@ -85,27 +109,7 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
md4_digest(ctx, MD4_DIGEST_SIZE, result);
}
-/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
-#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4)
-#include <wolfssl/openssl/md4.h>
-
-#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
-#include <openssl/md4.h>
-
-#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
- (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
- defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
- (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
- (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
- (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
-
-#include <CommonCrypto/CommonDigest.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
+#elif defined(AN_APPLE_OS)
typedef CC_MD4_CTX MD4_CTX;
static void MD4_Init(MD4_CTX *ctx)
@@ -125,13 +129,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
#elif defined(USE_WIN32_CRYPTO)
-#include <wincrypt.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
struct md4_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
@@ -171,13 +168,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
#elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C))
-#include <mbedtls/md4.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
struct md4_ctx {
void *data;
unsigned long size;
@@ -255,9 +245,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
* compile-time configuration.
*/
-
-#include <string.h>
-
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD4_u32plus;
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 5be6399..9610e0c 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.c
@@ -26,6 +26,7 @@
#ifndef CURL_DISABLE_CRYPTO_AUTH
+#include <string.h>
#include <curl/curl.h>
#include "curl_md5.h"
@@ -56,12 +57,32 @@
#endif
#if defined(USE_GNUTLS)
-
#include <nettle/md5.h>
+#elif defined(USE_OPENSSL_MD5)
+#include <openssl/md5.h>
+#elif defined(USE_WOLFSSL_MD5)
+#include <wolfssl/openssl/md5.h>
+#elif defined(USE_MBEDTLS)
+#include <mbedtls/md5.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+ defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+#define AN_APPLE_OS
+#include <CommonCrypto/CommonDigest.h>
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
#include "curl_memory.h"
-/* The last #include file should be: */
#include "memdebug.h"
+#if defined(USE_GNUTLS)
+
typedef struct md5_ctx my_md5_ctx;
static CURLcode my_md5_init(my_md5_ctx *ctx)
@@ -84,17 +105,6 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
-/* When OpenSSL or wolfSSL is available, we use their MD5 functions. */
-#if defined(USE_OPENSSL_MD5)
-#include <openssl/md5.h>
-#elif defined(USE_WOLFSSL_MD5)
-#include <wolfssl/openssl/md5.h>
-#endif
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
typedef MD5_CTX my_md5_ctx;
static CURLcode my_md5_init(my_md5_ctx *ctx)
@@ -119,13 +129,6 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
#elif defined(USE_MBEDTLS)
-#include <mbedtls/md5.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
typedef mbedtls_md5_context my_md5_ctx;
static CURLcode my_md5_init(my_md5_ctx *ctx)
@@ -162,12 +165,7 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
#endif
}
-#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
- (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
- defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
- (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
- (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
- (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+#elif defined(AN_APPLE_OS)
/* For Apple operating systems: CommonCrypto has the functions we need.
These functions are available on Tiger and later, as well as iOS 2.0
@@ -175,11 +173,7 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
Declaring the functions as static like this seems to be a bit more
reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
-# include <CommonCrypto/CommonDigest.h>
# define my_md5_ctx CC_MD5_CTX
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
static CURLcode my_md5_init(my_md5_ctx *ctx)
{
@@ -203,11 +197,6 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
#elif defined(USE_WIN32_CRYPTO)
-#include <wincrypt.h>
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
struct md5_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
@@ -288,12 +277,6 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
* compile-time configuration.
*/
-#include <string.h>
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index 042141f..e3f2821d 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -1175,7 +1175,7 @@ void Curl_mime_cleanpart(curl_mimepart *part)
Curl_safefree(part->mimetype);
Curl_safefree(part->name);
Curl_safefree(part->filename);
- Curl_mime_initpart(part, part->easy);
+ Curl_mime_initpart(part);
}
/* Recursively delete a mime handle and its parts. */
@@ -1195,7 +1195,8 @@ void curl_mime_free(curl_mime *mime)
}
}
-CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
+CURLcode Curl_mime_duppart(struct Curl_easy *data,
+ curl_mimepart *dst, const curl_mimepart *src)
{
curl_mime *mime;
curl_mimepart *d;
@@ -1224,13 +1225,13 @@ CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
case MIMEKIND_MULTIPART:
/* No one knows about the cloned subparts, thus always attach ownership
to the part. */
- mime = curl_mime_init(dst->easy);
+ mime = curl_mime_init(data);
res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
/* Duplicate subparts. */
for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
d = curl_mime_addpart(mime);
- res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY;
+ res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
}
break;
default: /* Invalid kind: should not occur. */
@@ -1282,7 +1283,6 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
mime = (curl_mime *) malloc(sizeof(*mime));
if(mime) {
- mime->easy = easy;
mime->parent = NULL;
mime->firstpart = NULL;
mime->lastpart = NULL;
@@ -1302,10 +1302,9 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
}
/* Initialize a mime part. */
-void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
+void Curl_mime_initpart(curl_mimepart *part)
{
memset((char *) part, 0, sizeof(*part));
- part->easy = easy;
part->lastreadstatus = 1; /* Successful read status. */
mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
}
@@ -1321,7 +1320,7 @@ curl_mimepart *curl_mime_addpart(curl_mime *mime)
part = (curl_mimepart *) malloc(sizeof(*part));
if(part) {
- Curl_mime_initpart(part, mime->easy);
+ Curl_mime_initpart(part);
part->parent = mime;
if(mime->lastpart)
@@ -1551,10 +1550,6 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
cleanup_part_content(part);
if(subparts) {
- /* Must belong to the same data handle. */
- if(part->easy && subparts->easy && part->easy != subparts->easy)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
/* Should not have been attached already. */
if(subparts->parent)
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -1565,8 +1560,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
while(root->parent && root->parent->parent)
root = root->parent->parent;
if(subparts == root) {
- if(part->easy)
- failf(part->easy, "Can't add itself as a subpart");
+ /* Can't add as a subpart of itself. */
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
@@ -1636,7 +1630,7 @@ static size_t slist_size(struct curl_slist *s,
static curl_off_t multipart_size(curl_mime *mime)
{
curl_off_t size;
- size_t boundarysize;
+ curl_off_t boundarysize;
curl_mimepart *part;
if(!mime)
@@ -1766,7 +1760,8 @@ static bool content_type_match(const char *contenttype,
return FALSE;
}
-CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
+ curl_mimepart *part,
const char *contenttype,
const char *disposition,
enum mimestrategy strategy)
@@ -1835,12 +1830,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
char *filename = NULL;
if(part->name) {
- name = escape_string(part->easy, part->name, strategy);
+ name = escape_string(data, part->name, strategy);
if(!name)
ret = CURLE_OUT_OF_MEMORY;
}
if(!ret && part->filename) {
- filename = escape_string(part->easy, part->filename, strategy);
+ filename = escape_string(data, part->filename, strategy);
if(!filename)
ret = CURLE_OUT_OF_MEMORY;
}
@@ -1897,7 +1892,8 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
if(content_type_match(contenttype, STRCONST("multipart/form-data")))
disposition = "form-data";
for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
- ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
+ ret = Curl_mime_prepare_headers(data, subpart, NULL,
+ disposition, strategy);
if(ret)
return ret;
}
diff --git a/Utilities/cmcurl/lib/mime.h b/Utilities/cmcurl/lib/mime.h
index bafde29..b9ea0f1 100644
--- a/Utilities/cmcurl/lib/mime.h
+++ b/Utilities/cmcurl/lib/mime.h
@@ -99,7 +99,6 @@ struct mime_state {
/* A mime multipart. */
struct curl_mime {
- struct Curl_easy *easy; /* The associated easy handle. */
curl_mimepart *parent; /* Parent part. */
curl_mimepart *firstpart; /* First part. */
curl_mimepart *lastpart; /* Last part. */
@@ -109,7 +108,6 @@ struct curl_mime {
/* A mime part. */
struct curl_mimepart {
- struct Curl_easy *easy; /* The associated easy handle. */
curl_mime *parent; /* Parent mime structure. */
curl_mimepart *nextpart; /* Forward linked list. */
enum mimekind kind; /* The part kind. */
@@ -139,14 +137,16 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
!defined(CURL_DISABLE_IMAP))
/* Prototypes. */
-void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy);
+void Curl_mime_initpart(struct curl_mimepart *part);
void Curl_mime_cleanpart(struct curl_mimepart *part);
-CURLcode Curl_mime_duppart(struct curl_mimepart *dst,
+CURLcode Curl_mime_duppart(struct Curl_easy *data,
+ struct curl_mimepart *dst,
const curl_mimepart *src);
CURLcode Curl_mime_set_subparts(struct curl_mimepart *part,
struct curl_mime *subparts,
int take_ownership);
-CURLcode Curl_mime_prepare_headers(struct curl_mimepart *part,
+CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
+ struct curl_mimepart *part,
const char *contenttype,
const char *disposition,
enum mimestrategy strategy);
@@ -159,11 +159,11 @@ void Curl_mime_unpause(struct curl_mimepart *part);
#else
/* if disabled */
-#define Curl_mime_initpart(x,y)
+#define Curl_mime_initpart(x)
#define Curl_mime_cleanpart(x)
-#define Curl_mime_duppart(x,y) CURLE_OK /* Nothing to duplicate. Succeed */
+#define Curl_mime_duppart(x,y,z) CURLE_OK /* Nothing to duplicate. Succeed */
#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
-#define Curl_mime_prepare_headers(a,b,c,d) CURLE_NOT_BUILT_IN
+#define Curl_mime_prepare_headers(a,b,c,d,e) CURLE_NOT_BUILT_IN
#define Curl_mime_size(x) (curl_off_t) -1
#define Curl_mime_read NULL
#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN)
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 4f3d143..8ba826f 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -242,7 +242,7 @@ static int init_connpack(char *packet, char *remain, int remain_pos)
/* keep-alive 0 = disabled */
packet[remain_pos + 9] = 0x00;
packet[remain_pos + 10] = 0x3c;
- /*end of variable header*/
+ /* end of variable header */
return remain_pos + 10;
}
@@ -251,7 +251,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
CURLcode result = CURLE_OK;
int pos = 0;
int rc = 0;
- /*remain length*/
+ /* remain length */
int remain_pos = 0;
char remain[4] = {0};
size_t packetlen = 0;
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 51acba7..b96ee7c 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -29,6 +29,7 @@
#include "urldata.h"
#include "transfer.h"
#include "url.h"
+#include "cfilters.h"
#include "connect.h"
#include "progress.h"
#include "easyif.h"
@@ -160,7 +161,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL, /* TUNNELING */
NULL, /* PROTOCONNECT */
NULL, /* PROTOCONNECTING */
- Curl_connect_free, /* DO */
+ NULL, /* DO */
NULL, /* DOING */
NULL, /* DOING_MORE */
before_perform, /* DID */
@@ -709,6 +710,11 @@ static CURLcode multi_done(struct Curl_easy *data,
#endif
) || conn->bits.close
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
+ DEBUGF(infof(data, "multi_done, not re-using connection=%ld, forbid=%d"
+ ", close=%d, premature=%d, stream=%d",
+ conn->connection_id,
+ data->set.reuse_forbid, conn->bits.close, premature,
+ (conn->handler->flags & PROTOPT_STREAM)));
connclose(conn, "disconnecting");
Curl_conncache_remove_conn(data, conn, FALSE);
CONNCACHE_UNLOCK(data);
@@ -948,9 +954,8 @@ void Curl_detach_connection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
if(conn) {
- Curl_connect_done(data); /* if mid-CONNECT, shut it down */
+ Curl_conn_detach_data(conn, data);
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
- Curl_ssl_detach_conn(data, conn);
}
data->conn = NULL;
}
@@ -968,53 +973,9 @@ void Curl_attach_connection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
+ Curl_conn_attach_data(conn, data);
if(conn->handler->attach)
conn->handler->attach(data, conn);
- Curl_ssl_associate_conn(data, conn);
-}
-
-static int waitconnect_getsock(struct connectdata *conn,
- curl_socket_t *sock)
-{
- int i;
- int s = 0;
- int rc = 0;
-
-#ifdef USE_SSL
-#ifndef CURL_DISABLE_PROXY
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- return Curl_ssl->getsock(conn, sock);
-#endif
-#endif
-
- if(SOCKS_STATE(conn->cnnct.state))
- return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET);
-
- for(i = 0; i<2; i++) {
- if(conn->tempsock[i] != CURL_SOCKET_BAD) {
- sock[s] = conn->tempsock[i];
- rc |= GETSOCK_WRITESOCK(s);
-#ifdef ENABLE_QUIC
- if(conn->transport == TRNSPRT_QUIC)
- /* when connecting QUIC, we want to read the socket too */
- rc |= GETSOCK_READSOCK(s);
-#endif
- s++;
- }
- }
-
- return rc;
-}
-
-static int waitproxyconnect_getsock(struct connectdata *conn,
- curl_socket_t *sock)
-{
- sock[0] = conn->sock[FIRSTSOCKET];
-
- if(conn->connect_state)
- return Curl_connect_getsock(conn);
-
- return GETSOCK_WRITESOCK(0);
}
static int domore_getsock(struct Curl_easy *data,
@@ -1076,10 +1037,8 @@ static int multi_getsock(struct Curl_easy *data,
return doing_getsock(data, conn, socks);
case MSTATE_TUNNELING:
- return waitproxyconnect_getsock(conn, socks);
-
case MSTATE_CONNECTING:
- return waitconnect_getsock(conn, socks);
+ return Curl_conn_get_select_socks(data, FIRSTSOCKET, socks);
case MSTATE_DOING_MORE:
return domore_getsock(data, conn, socks);
@@ -1737,7 +1696,8 @@ static CURLcode protocol_connect(struct Curl_easy *data,
*protocol_done = FALSE;
- if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
+ if(Curl_conn_is_connected(conn, FIRSTSOCKET)
+ && conn->bits.protoconnstart) {
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
or proxy. Note that we don't know if the protocol is actually done.
@@ -1751,21 +1711,6 @@ static CURLcode protocol_connect(struct Curl_easy *data,
}
if(!conn->bits.protoconnstart) {
-#ifndef CURL_DISABLE_PROXY
- result = Curl_proxy_connect(data, FIRSTSOCKET);
- if(result)
- return result;
-
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- /* wait for HTTPS proxy SSL initialization to complete */
- return CURLE_OK;
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- /* when using an HTTP tunnel proxy, await complete tunnel establishment
- before proceeding further. Return CURLE_OK so we'll be called again */
- return CURLE_OK;
-#endif
if(conn->handler->connect_it) {
/* is there a protocol-specific connect() procedure? */
@@ -1785,6 +1730,90 @@ static CURLcode protocol_connect(struct Curl_easy *data,
}
/*
+ * readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+static CURLcode readrewind(struct Curl_easy *data)
+{
+ struct connectdata *conn = data->conn;
+ curl_mimepart *mimepart = &data->set.mimepost;
+ DEBUGASSERT(conn);
+
+ data->state.rewindbeforesend = FALSE; /* we rewind now */
+
+ /* explicitly switch off sending data on this connection now since we are
+ about to restart a new transfer and thus we want to avoid inadvertently
+ sending more data on the existing connection until the next transfer
+ starts */
+ data->req.keepon &= ~KEEP_SEND;
+
+ /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ struct HTTP *http = data->req.p.http;
+
+ if(http->sendit)
+ mimepart = http->sendit;
+ }
+ if(data->set.postfields ||
+ (data->state.httpreq == HTTPREQ_GET) ||
+ (data->state.httpreq == HTTPREQ_HEAD))
+ ; /* no need to rewind */
+ else if(data->state.httpreq == HTTPREQ_POST_MIME ||
+ data->state.httpreq == HTTPREQ_POST_FORM) {
+ CURLcode result = Curl_mime_rewind(mimepart);
+ if(result) {
+ failf(data, "Cannot rewind mime/post data");
+ return result;
+ }
+ }
+ else {
+ if(data->set.seek_func) {
+ int err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+ Curl_set_in_callback(data, false);
+ if(err) {
+ failf(data, "seek callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else if(data->set.ioctl_func) {
+ curlioerr err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+ data->set.ioctl_client);
+ Curl_set_in_callback(data, false);
+ infof(data, "the ioctl callback returned %d", (int)err);
+
+ if(err) {
+ failf(data, "ioctl callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else {
+ /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+ given FILE * stream and we can actually attempt to rewind that
+ ourselves with fseek() */
+ if(data->state.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->state.in, 0, SEEK_SET))
+ /* successful rewind */
+ return CURLE_OK;
+ }
+
+ /* no callback set or failure above, makes us fail at once */
+ failf(data, "necessary data rewind wasn't possible");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
* Curl_preconnect() is called immediately before a connect starts. When a
* redirect is followed, this is then called multiple times during a single
* transfer.
@@ -1796,6 +1825,7 @@ CURLcode Curl_preconnect(struct Curl_easy *data)
if(!data->state.buffer)
return CURLE_OUT_OF_MEMORY;
}
+
return CURLE_OK;
}
@@ -1901,7 +1931,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->set.connecttimeout)
Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
- result = Curl_connect(data, &async, &protocol_connected);
+ result = Curl_connect(data, &async, &connected);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
@@ -1929,15 +1959,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
WAITDO or DO! */
rc = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connected)
- multistate(data, MSTATE_DO);
+ if(connected)
+ multistate(data, MSTATE_PROTOCONNECT);
else {
-#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->conn))
- multistate(data, MSTATE_TUNNELING);
- else
-#endif
- multistate(data, MSTATE_CONNECTING);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -1989,7 +2014,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
- result = Curl_once_resolved(data, &protocol_connected);
+ result = Curl_once_resolved(data, &connected);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct
@@ -1998,15 +2023,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connected)
- multistate(data, MSTATE_DO);
+ if(connected)
+ multistate(data, MSTATE_PROTOCONNECT);
else {
-#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->conn))
- multistate(data, MSTATE_TUNNELING);
- else
-#endif
- multistate(data, MSTATE_CONNECTING);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -2035,16 +2055,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else
#endif
if(!result) {
- if(
-#ifndef CURL_DISABLE_PROXY
- (data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
- data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
-#endif
- Curl_connect_complete(data->conn)) {
- rc = CURLM_CALL_MULTI_PERFORM;
- /* initiate protocol connect phase */
- multistate(data, MSTATE_PROTOCONNECT);
- }
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* initiate protocol connect phase */
+ multistate(data, MSTATE_PROTOCONNECT);
}
else
stream_error = TRUE;
@@ -2054,27 +2067,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
- result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
if(connected && !result) {
-#ifndef CURL_DISABLE_HTTP
- if(
-#ifndef CURL_DISABLE_PROXY
- (data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
- !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
-#endif
- Curl_connect_ongoing(data->conn)) {
- multistate(data, MSTATE_TUNNELING);
- break;
- }
-#endif
rc = CURLM_CALL_MULTI_PERFORM;
-#ifndef CURL_DISABLE_PROXY
- multistate(data,
- data->conn->bits.tunnel_proxy?
- MSTATE_TUNNELING : MSTATE_PROTOCONNECT);
-#else
multistate(data, MSTATE_PROTOCONNECT);
-#endif
}
else if(result) {
/* failure detected */
@@ -2086,7 +2082,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_PROTOCONNECT:
- result = protocol_connect(data, &protocol_connected);
+ if(data->state.rewindbeforesend)
+ result = readrewind(data);
+
+ if(!result && data->conn->bits.reuse) {
+ /* ftp seems to hang when protoconnect on reused connection
+ * since we handle PROTOCONNECT in general inside the filers, it
+ * seems wrong to restart this on a reused connection. */
+ multistate(data, MSTATE_DO);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ break;
+ }
+ if(!result)
+ result = protocol_connect(data, &protocol_connected);
if(!result && !protocol_connected)
/* switch to waiting state */
multistate(data, MSTATE_PROTOCONNECTING);
@@ -2770,6 +2778,11 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
wakeup_close(multi->wakeup_pair[1]);
#endif
#endif
+
+#ifdef USE_SSL
+ Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
+#endif
+
free(multi);
return CURLM_OK;
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index a997784..5a83656 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -79,6 +79,10 @@ typedef enum {
/* value for MAXIMUM CONCURRENT STREAMS upper limit */
#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+ backend */
+struct multi_ssl_backend_data;
+
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to easier detect if a user mix up
@@ -118,6 +122,10 @@ struct Curl_multi {
times of all currently set timers */
struct Curl_tree *timetree;
+#if defined(USE_SSL)
+ struct multi_ssl_backend_data *ssl_backend_data;
+#endif
+
/* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
the pluralis form, there can be more than one easy handle waiting on the
same actual socket) */
diff --git a/Utilities/cmcurl/lib/nonblock.c b/Utilities/cmcurl/lib/nonblock.c
index ce73af3..8447b6f 100644
--- a/Utilities/cmcurl/lib/nonblock.c
+++ b/Utilities/cmcurl/lib/nonblock.c
@@ -31,9 +31,6 @@
#include <fcntl.h>
#endif
-#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
-#include <sys/filio.h>
-#endif
#ifdef __VMS
#include <in.h>
#include <inet.h>
diff --git a/Utilities/cmcurl/lib/noproxy.c b/Utilities/cmcurl/lib/noproxy.c
index 7c4f4d5..9b13fe8 100644
--- a/Utilities/cmcurl/lib/noproxy.c
+++ b/Utilities/cmcurl/lib/noproxy.c
@@ -34,6 +34,10 @@
#include <netinet/in.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
/*
* Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
* specified CIDR address range.
@@ -213,18 +217,22 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
/* FALLTHROUGH */
case TYPE_IPV6: {
const char *check = token;
- char *slash = strchr(check, '/');
+ char *slash;
unsigned int bits = 0;
char checkip[128];
+ if(tokenlen >= sizeof(checkip))
+ /* this cannot match */
+ break;
+ /* copy the check name to a temp buffer */
+ memcpy(checkip, check, tokenlen);
+ checkip[tokenlen] = 0;
+ check = checkip;
+
+ slash = strchr(check, '/');
/* if the slash is part of this token, use it */
- if(slash && (slash < &check[tokenlen])) {
+ if(slash) {
bits = atoi(slash + 1);
- /* copy the check name to a temp buffer */
- if(tokenlen >= sizeof(checkip))
- break;
- memcpy(checkip, check, tokenlen);
- checkip[ slash - check ] = 0;
- check = checkip;
+ *slash = 0; /* null terminate there */
}
if(type == TYPE_IPV6)
match = Curl_cidr6_match(name, check, bits);
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index 3a93b67..ab81e57 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -47,6 +47,7 @@
#include "transfer.h"
#include "curl_ldap.h"
#include "curl_base64.h"
+#include "cfilters.h"
#include "connect.h"
#include "curl_sasl.h"
#include "strcase.h"
@@ -500,8 +501,7 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
struct ldapconninfo *li = conn->proto.ldapc;
bool ssldone = 0;
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &ssldone);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
if(!result) {
state(data, newstate);
@@ -1153,7 +1153,7 @@ ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
(void)arg;
if(opt == LBER_SB_OPT_DATA_READY) {
struct Curl_easy *data = sbiod->sbiod_pvt;
- return Curl_ssl_data_pending(data->conn, FIRSTSOCKET);
+ return Curl_conn_data_pending(data, FIRSTSOCKET);
}
return 0;
}
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
index d4e6be9..9b95580 100644
--- a/Utilities/cmcurl/lib/pingpong.c
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -28,6 +28,7 @@
#include "curl_setup.h"
#include "urldata.h"
+#include "cfilters.h"
#include "sendf.h"
#include "select.h"
#include "progress.h"
@@ -102,12 +103,12 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
else
interval_ms = 0; /* immediate */
- if(Curl_ssl_data_pending(conn, FIRSTSOCKET))
+ if(Curl_conn_data_pending(data, FIRSTSOCKET))
rc = 1;
else if(Curl_pp_moredata(pp))
/* We are receiving and there is data in the cache so just read it */
rc = 1;
- else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET))
+ else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
/* We are receiving and there is data ready in the SSL library */
rc = 1;
else
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index 3151a3f..ce17f2a 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -58,11 +58,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -76,6 +71,7 @@
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "select.h"
#include "multiif.h"
@@ -373,9 +369,15 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
{
/* Start the SSL connection */
struct pop3_conn *pop3c = &conn->proto.pop3c;
- CURLcode result =
- Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET,
- &pop3c->ssldone);
+ CURLcode result;
+
+ if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
+ result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+ if(result)
+ goto out;
+ }
+
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &pop3c->ssldone);
if(!result) {
if(pop3c->state != POP3_UPGRADETLS)
@@ -386,7 +388,7 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
result = pop3_perform_capa(data, conn);
}
}
-
+out:
return result;
}
@@ -767,7 +769,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
if(pop3code != '+')
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
- if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use)
+ if(!data->set.use_ssl || Curl_conn_is_ssl(data, FIRSTSOCKET))
result = pop3_perform_authentication(data, conn);
else if(pop3code == '+' && pop3c->tls_supported)
/* Switch to TLS connection now */
@@ -948,7 +950,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
content so send it as such. Note that there may even be additional
"headers" after the body */
- if(!data->set.opt_no_body) {
+ if(!data->req.no_body) {
result = Curl_pop3_write(data, pp->cache, pp->cache_size);
if(result)
return result;
@@ -1054,8 +1056,7 @@ static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
struct pop3_conn *pop3c = &conn->proto.pop3c;
if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &pop3c->ssldone);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &pop3c->ssldone);
if(result || !pop3c->ssldone)
return result;
}
@@ -1192,12 +1193,11 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
{
/* This is POP3 and no proxy */
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct POP3 *pop3 = data->req.p.pop3;
DEBUGF(infof(data, "DO phase starts"));
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* Requested no body means no transfer */
pop3->transfer = PPTRANSFER_INFO;
}
@@ -1211,7 +1211,7 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
/* Run the state-machine */
result = pop3_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index 2e7e7e8..a549624 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.c
@@ -27,10 +27,14 @@
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
#include <curl/curl.h>
#include "vtls/vtls.h"
#include "sendf.h"
+#include "timeval.h"
#include "rand.h"
/* The last 3 #include files should be in this order */
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index 6d3bf97..75e620d 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -141,7 +141,7 @@ static CURLcode rtsp_setup_connection(struct Curl_easy *data,
* Instead, if it is readable, run Curl_connalive() to peek at the socket
* and distinguish between closed and data.
*/
-static bool rtsp_connisdead(struct connectdata *check)
+static bool rtsp_connisdead(struct Curl_easy *data, struct connectdata *check)
{
int sval;
bool ret_val = TRUE;
@@ -157,7 +157,7 @@ static bool rtsp_connisdead(struct connectdata *check)
}
else if(sval & CURL_CSELECT_IN) {
/* readable with no error. could still be closed */
- ret_val = !Curl_connalive(check);
+ ret_val = !Curl_connalive(data, check);
}
return ret_val;
@@ -174,7 +174,7 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
(void)data;
if(checks_to_perform & CONNCHECK_ISDEAD) {
- if(rtsp_connisdead(conn))
+ if(rtsp_connisdead(data, conn))
ret_val |= CONNRESULT_DEAD;
}
@@ -267,11 +267,23 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
rtsp->CSeq_recv = 0;
+ /* Setup the first_* fields to allow auth details get sent
+ to this origin */
+
+ if(!data->state.first_host) {
+ data->state.first_host = strdup(conn->host.name);
+ if(!data->state.first_host)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->state.first_remote_port = conn->remote_port;
+ data->state.first_remote_protocol = conn->handler->protocol;
+ }
+
/* Setup the 'p_request' pointer to the proper p_request string
* Since all RTSP requests are included here, there is no need to
* support custom requests like HTTP.
**/
- data->set.opt_no_body = TRUE; /* most requests don't contain a body */
+ data->req.no_body = TRUE; /* most requests don't contain a body */
switch(rtspreq) {
default:
failf(data, "Got invalid RTSP request");
@@ -281,7 +293,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
break;
case RTSPREQ_DESCRIBE:
p_request = "DESCRIBE";
- data->set.opt_no_body = FALSE;
+ data->req.no_body = FALSE;
break;
case RTSPREQ_ANNOUNCE:
p_request = "ANNOUNCE";
@@ -301,7 +313,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
case RTSPREQ_GET_PARAMETER:
/* GET_PARAMETER's no_body status is determined later */
p_request = "GET_PARAMETER";
- data->set.opt_no_body = FALSE;
+ data->req.no_body = FALSE;
break;
case RTSPREQ_SET_PARAMETER:
p_request = "SET_PARAMETER";
@@ -311,8 +323,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
break;
case RTSPREQ_RECEIVE:
p_request = "";
- /* Treat interleaved RTP as body*/
- data->set.opt_no_body = FALSE;
+ /* Treat interleaved RTP as body */
+ data->req.no_body = FALSE;
break;
case RTSPREQ_LAST:
failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
@@ -561,7 +573,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
else if(rtspreq == RTSPREQ_GET_PARAMETER) {
/* Check for an empty GET_PARAMETER (heartbeat) request */
data->state.httpreq = HTTPREQ_HEAD;
- data->set.opt_no_body = TRUE;
+ data->req.no_body = TRUE;
}
}
@@ -650,7 +662,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
rtp_length = RTP_PKT_LENGTH(rtp);
if(rtp_dataleft < rtp_length + 4) {
- /* Need more - incomplete payload*/
+ /* Need more - incomplete payload */
*readmore = TRUE;
break;
}
diff --git a/Utilities/cmcurl/lib/rtsp.h b/Utilities/cmcurl/lib/rtsp.h
index 377c828..fa6606a 100644
--- a/Utilities/cmcurl/lib/rtsp.h
+++ b/Utilities/cmcurl/lib/rtsp.h
@@ -62,7 +62,7 @@ struct RTSP {
* HTTP functions can safely treat this as an HTTP struct, but RTSP aware
* functions can also index into the later elements.
*/
- struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */
+ struct HTTP http_wrapper; /* wrap HTTP to do the heavy lifting */
long CSeq_sent; /* CSeq of this request */
long CSeq_recv; /* CSeq received */
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index d26b7e7..6326240 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -38,6 +38,7 @@
#include "urldata.h"
#include "sendf.h"
+#include "cfilters.h"
#include "connect.h"
#include "vtls/vtls.h"
#include "vssh/ssh.h"
@@ -151,13 +152,15 @@ static CURLcode pre_receive_plain(struct Curl_easy *data,
const curl_socket_t sockfd = conn->sock[num];
struct postponed_data * const psnd = &(conn->postponed[num]);
size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
+ ssize_t recvedbytes;
+
/* WinSock will destroy unread received data if send() is
failed.
To avoid lossage of received data, recv() must be
performed before every send() if any incoming data is
available. However, skip this, if buffer is already full. */
if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
- conn->recv[num] == Curl_recv_plain &&
+ conn->recv[num] == Curl_conn_recv &&
(!psnd->buffer || bytestorecv)) {
const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
CURL_SOCKET_BAD, 0);
@@ -176,16 +179,12 @@ static CURLcode pre_receive_plain(struct Curl_easy *data,
#endif /* DEBUGBUILD */
bytestorecv = psnd->allocated_size;
}
- if(psnd->buffer) {
- ssize_t recvedbytes;
- DEBUGASSERT(psnd->bindsock == sockfd);
- recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
- bytestorecv);
- if(recvedbytes > 0)
- psnd->recv_size += recvedbytes;
- }
- else
- psnd->allocated_size = 0;
+
+ DEBUGASSERT(psnd->bindsock == sockfd);
+ recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
+ bytestorecv);
+ if(recvedbytes > 0)
+ psnd->recv_size += recvedbytes;
}
}
return CURLE_OK;
@@ -339,6 +338,7 @@ CURLcode Curl_write(struct Curl_easy *data,
}
}
+/* Curl_send_plain sends raw data without a size restriction on 'len'. */
ssize_t Curl_send_plain(struct Curl_easy *data, int num,
const void *mem, size_t len, CURLcode *code)
{
@@ -387,7 +387,6 @@ ssize_t Curl_send_plain(struct Curl_easy *data, int num,
#endif
) {
/* this is just a case of EWOULDBLOCK */
- bytes_written = 0;
*code = CURLE_AGAIN;
}
else {
@@ -404,7 +403,12 @@ ssize_t Curl_send_plain(struct Curl_easy *data, int num,
/*
* Curl_write_plain() is an internal write function that sends data to the
* server using plain sockets only. Otherwise meant to have the exact same
- * proto as Curl_write()
+ * proto as Curl_write().
+ *
+ * This function wraps Curl_send_plain(). The only difference besides the
+ * prototype is '*written' (bytes written) is set to 0 on error.
+ * 'sockfd' must be one of the connection's two main sockets and the value of
+ * 'len' must not be changed.
*/
CURLcode Curl_write_plain(struct Curl_easy *data,
curl_socket_t sockfd,
@@ -416,13 +420,22 @@ CURLcode Curl_write_plain(struct Curl_easy *data,
struct connectdata *conn = data->conn;
int num;
DEBUGASSERT(conn);
+ DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
+ sockfd == conn->sock[SECONDARYSOCKET]);
+ if(sockfd != conn->sock[FIRSTSOCKET] &&
+ sockfd != conn->sock[SECONDARYSOCKET])
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
num = (sockfd == conn->sock[SECONDARYSOCKET]);
*written = Curl_send_plain(data, num, mem, len, &result);
+ if(*written == -1)
+ *written = 0;
return result;
}
+/* Curl_recv_plain receives raw data without a size restriction on 'len'. */
ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code)
{
@@ -664,30 +677,39 @@ CURLcode Curl_client_write(struct Curl_easy *data,
return chop_write(data, type, ptr, len);
}
-CURLcode Curl_read_plain(curl_socket_t sockfd,
- char *buf,
- size_t bytesfromsocket,
- ssize_t *n)
+/*
+ * Curl_read_plain() is an internal read function that reads data from the
+ * server using plain sockets only. Otherwise meant to have the exact same
+ * proto as Curl_read().
+ *
+ * This function wraps Curl_recv_plain(). The only difference besides the
+ * prototype is '*n' (bytes read) is set to 0 on error.
+ * 'sockfd' must be one of the connection's two main sockets and the value of
+ * 'sizerequested' must not be changed.
+ */
+CURLcode Curl_read_plain(struct Curl_easy *data, /* transfer */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ size_t sizerequested, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
{
- ssize_t nread = sread(sockfd, buf, bytesfromsocket);
+ CURLcode result;
+ struct connectdata *conn = data->conn;
+ int num;
+ DEBUGASSERT(conn);
+ DEBUGASSERT(sockfd == conn->sock[FIRSTSOCKET] ||
+ sockfd == conn->sock[SECONDARYSOCKET]);
+ if(sockfd != conn->sock[FIRSTSOCKET] &&
+ sockfd != conn->sock[SECONDARYSOCKET])
+ return CURLE_BAD_FUNCTION_ARGUMENT;
- if(-1 == nread) {
- const int err = SOCKERRNO;
- const bool return_error =
-#ifdef USE_WINSOCK
- WSAEWOULDBLOCK == err
-#else
- EWOULDBLOCK == err || EAGAIN == err || EINTR == err
-#endif
- ;
- *n = 0; /* no data returned */
- if(return_error)
- return CURLE_AGAIN;
- return CURLE_RECV_ERROR;
- }
+ num = (sockfd == conn->sock[SECONDARYSOCKET]);
- *n = nread;
- return CURLE_OK;
+ *n = Curl_recv_plain(data, num, buf, sizerequested, &result);
+ if(*n == -1)
+ *n = 0;
+
+ return result;
}
/*
@@ -720,11 +742,14 @@ CURLcode Curl_read(struct Curl_easy *data, /* transfer */
nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
if(nread < 0)
- return result;
+ goto out;
*n += nread;
-
- return CURLE_OK;
+ result = CURLE_OK;
+out:
+ /* DEBUGF(infof(data, "Curl_read(handle=%p) -> %d, nread=%ld",
+ data, result, nread)); */
+ return result;
}
/* return 0 on success */
diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h
index 7c4c128..8af5c46 100644
--- a/Utilities/cmcurl/lib/sendf.h
+++ b/Utilities/cmcurl/lib/sendf.h
@@ -61,9 +61,10 @@ CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex);
/* internal read-function, does plain socket only */
-CURLcode Curl_read_plain(curl_socket_t sockfd,
+CURLcode Curl_read_plain(struct Curl_easy *data,
+ curl_socket_t sockfd,
char *buf,
- size_t bytesfromsocket,
+ size_t sizerequested,
ssize_t *n);
ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 5b59754..b77e95b 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -204,6 +204,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.dns_cache_timeout = (int)arg;
break;
+ case CURLOPT_CA_CACHE_TIMEOUT:
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ else if(arg > INT_MAX)
+ arg = INT_MAX;
+
+ data->set.general_ssl.ca_cache_timeout = (int)arg;
+ break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
/* deprecated */
break;
@@ -220,7 +229,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
case CURLOPT_TLS13_CIPHERS:
- if(Curl_ssl_tls13_ciphersuites()) {
+ if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
/* set preferred list of TLS 1.3 cipher suites */
result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
va_arg(param, char *));
@@ -230,7 +239,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_TLS13_CIPHERS:
- if(Curl_ssl_tls13_ciphersuites()) {
+ if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
/* set preferred list of TLS 1.3 cipher suites for proxy */
result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY],
va_arg(param, char *));
@@ -406,7 +415,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.timecondition = (curl_TimeCond)arg;
+ data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
break;
case CURLOPT_TIMEVALUE:
/*
@@ -598,7 +607,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_FOLLOWLOCATION:
/*
- * Follow Location: header hints on a HTTP-server.
+ * Follow Location: header hints on an HTTP-server.
*/
data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
@@ -914,7 +923,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_EXPECT_100_TIMEOUT_MS:
/*
- * Time to wait for a response to a HTTP request containing an
+ * Time to wait for a response to an HTTP request containing an
* Expect: 100-continue header before sending the data anyway.
*/
arg = va_arg(param, long);
@@ -1048,7 +1057,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < 0) || (arg > 65535))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.proxyport = arg;
+ data->set.proxyport = (unsigned short)arg;
break;
case CURLOPT_PROXYAUTH:
@@ -1135,7 +1144,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.proxytype = (curl_proxytype)arg;
+ data->set.proxytype = (unsigned char)(curl_proxytype)arg;
break;
case CURLOPT_PROXY_TRANSFER_MODE:
@@ -1157,7 +1166,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SOCKS5_AUTH:
- data->set.socks5auth = va_arg(param, unsigned long);
+ data->set.socks5auth = (unsigned char)va_arg(param, unsigned long);
if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
result = CURLE_NOT_BUILT_IN;
break;
@@ -1234,7 +1243,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftp_filemethod = (curl_ftpfile)arg;
+ data->set.ftp_filemethod = (unsigned char)(curl_ftpfile)arg;
break;
case CURLOPT_FTPPORT:
/*
@@ -1261,7 +1270,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftp_ccc = (curl_ftpccc)arg;
+ data->set.ftp_ccc = (unsigned char)(curl_ftpccc)arg;
break;
case CURLOPT_FTP_SKIP_PASV_IP:
@@ -1289,7 +1298,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.ftpsslauth = (curl_ftpauth)arg;
+ data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
break;
case CURLOPT_KRBLEVEL:
/*
@@ -1992,7 +2001,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set a SSL_CTX callback
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_SSL_CTX)
+ if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
else
#endif
@@ -2003,7 +2012,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set a SSL_CTX callback parameter pointer
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_SSL_CTX)
+ if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
data->set.ssl.fsslctxp = va_arg(param, void *);
else
#endif
@@ -2013,7 +2022,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Enable TLS false start.
*/
- if(!Curl_ssl_false_start()) {
+ if(!Curl_ssl_false_start(data)) {
result = CURLE_NOT_BUILT_IN;
break;
}
@@ -2022,7 +2031,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_CERTINFO:
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_CERTINFO)
+ if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
else
#endif
@@ -2034,7 +2043,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify file name of the public key in DER format.
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
+ if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
va_arg(param, char *));
else
@@ -2048,7 +2057,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify file name of the public key in DER format.
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
+ if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
va_arg(param, char *));
else
@@ -2069,7 +2078,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify entire PEM of the CA certificate
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+ if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
va_arg(param, struct curl_blob *));
else
@@ -2092,7 +2101,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Specify entire PEM of the CA certificate
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+ if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB))
result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
va_arg(param, struct curl_blob *));
else
@@ -2106,7 +2115,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* certificates which have been prepared using openssl c_rehash utility.
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_CA_PATH)
+ if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
/* This does not work on windows. */
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
va_arg(param, char *));
@@ -2121,7 +2130,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* CA certificates which have been prepared using openssl c_rehash utility.
*/
#ifdef USE_SSL
- if(Curl_ssl->supports & SSLSUPP_CA_PATH)
+ if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
/* This does not work on windows. */
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
va_arg(param, char *));
@@ -2205,7 +2214,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
else if(arg < READBUFFER_MIN)
arg = READBUFFER_MIN;
- data->set.buffer_size = (int)arg;
+ data->set.buffer_size = (unsigned int)arg;
break;
case CURLOPT_UPLOAD_BUFFERSIZE:
@@ -3107,6 +3116,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
#endif
+ case CURLOPT_QUICK_EXIT:
+ data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/Utilities/cmcurl/lib/setup-os400.h b/Utilities/cmcurl/lib/setup-os400.h
index 6023ca2..7854397 100644
--- a/Utilities/cmcurl/lib/setup-os400.h
+++ b/Utilities/cmcurl/lib/setup-os400.h
@@ -49,11 +49,11 @@ extern int Curl_getaddrinfo_a(const char *nodename,
struct addrinfo **res);
#define getaddrinfo Curl_getaddrinfo_a
-
+/* Note socklen_t must be used as this is declared before curl_socklen_t */
extern int Curl_getnameinfo_a(const struct sockaddr *sa,
- curl_socklen_t salen,
- char *nodename, curl_socklen_t nodenamelen,
- char *servname, curl_socklen_t servnamelen,
+ socklen_t salen,
+ char *nodename, socklen_t nodenamelen,
+ char *servname, socklen_t servnamelen,
int flags);
#define getnameinfo Curl_getnameinfo_a
diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c
index 60720f5..c96a9fc 100644
--- a/Utilities/cmcurl/lib/sha256.c
+++ b/Utilities/cmcurl/lib/sha256.c
@@ -57,18 +57,6 @@
#endif
#endif /* USE_MBEDTLS */
-/* Please keep the SSL backend-specific #if branches in this order:
- *
- * 1. USE_OPENSSL
- * 2. USE_GNUTLS
- * 3. USE_MBEDTLS
- * 4. USE_COMMON_CRYPTO
- * 5. USE_WIN32_CRYPTO
- *
- * This ensures that the same SSL branch gets activated throughout this source
- * file even if multiple backends are enabled at the same time.
- */
-
#if defined(USE_OPENSSL_SHA256)
/* When OpenSSL or wolfSSL is available is available we use their
@@ -80,11 +68,39 @@
#include <wolfssl/openssl/evp.h>
#endif
-#include "curl_memory.h"
+#elif defined(USE_GNUTLS)
+#include <nettle/sha.h>
+#elif defined(USE_MBEDTLS)
+#include <mbedtls/sha256.h>
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+#include <CommonCrypto/CommonDigest.h>
+#define AN_APPLE_OS
+#elif defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#endif
-/* The last #include file should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
#include "memdebug.h"
+/* Please keep the SSL backend-specific #if branches in this order:
+ *
+ * 1. USE_OPENSSL
+ * 2. USE_GNUTLS
+ * 3. USE_MBEDTLS
+ * 4. USE_COMMON_CRYPTO
+ * 5. USE_WIN32_CRYPTO
+ *
+ * This ensures that the same SSL branch gets activated throughout this source
+ * file even if multiple backends are enabled at the same time.
+ */
+
+#if defined(USE_OPENSSL_SHA256)
+
struct sha256_ctx {
EVP_MD_CTX *openssl_ctx;
};
@@ -115,13 +131,6 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
#elif defined(USE_GNUTLS)
-#include <nettle/sha.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
typedef struct sha256_ctx my_sha256_ctx;
static CURLcode my_sha256_init(my_sha256_ctx *ctx)
@@ -144,13 +153,6 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
#elif defined(USE_MBEDTLS)
-#include <mbedtls/sha256.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
typedef mbedtls_sha256_context my_sha256_ctx;
static CURLcode my_sha256_init(my_sha256_ctx *ctx)
@@ -183,18 +185,7 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
#endif
}
-#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
- (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
- (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
- (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
-
-#include <CommonCrypto/CommonDigest.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
+#elif defined(AN_APPLE_OS)
typedef CC_SHA256_CTX my_sha256_ctx;
static CURLcode my_sha256_init(my_sha256_ctx *ctx)
@@ -217,8 +208,6 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
#elif defined(USE_WIN32_CRYPTO)
-#include <wincrypt.h>
-
struct sha256_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index a62e858..48d5a2f 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -30,19 +30,15 @@
#define BUILDING_CURL_SMB_C
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#ifdef CURL_WINDOWS_APP
+#ifdef WIN32
#define getpid GetCurrentProcessId
-#elif defined(WIN32)
-#define getpid _getpid
-#endif
#endif
#include "smb.h"
#include "urldata.h"
#include "sendf.h"
#include "multiif.h"
+#include "cfilters.h"
#include "connect.h"
#include "progress.h"
#include "transfer.h"
@@ -62,8 +58,6 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done);
static CURLcode smb_connection_state(struct Curl_easy *data, bool *done);
static CURLcode smb_do(struct Curl_easy *data, bool *done);
static CURLcode smb_request_state(struct Curl_easy *data, bool *done);
-static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
- bool premature);
static CURLcode smb_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
@@ -78,7 +72,7 @@ const struct Curl_handler Curl_handler_smb = {
"SMB", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
- smb_done, /* done */
+ ZERO_NULL, /* done */
ZERO_NULL, /* do_more */
smb_connect, /* connect_it */
smb_connection_state, /* connecting */
@@ -105,7 +99,7 @@ const struct Curl_handler Curl_handler_smbs = {
"SMBS", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
- smb_done, /* done */
+ ZERO_NULL, /* done */
ZERO_NULL, /* do_more */
smb_connect, /* connect_it */
smb_connection_state, /* connecting */
@@ -671,8 +665,7 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
#ifdef USE_SSL
if((conn->handler->flags & PROTOPT_SSL)) {
bool ssl_done = FALSE;
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &ssl_done);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssl_done);
if(result && result != CURLE_AGAIN)
return result;
if(!ssl_done)
@@ -941,14 +934,6 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
return CURLE_OK;
}
-static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
- bool premature)
-{
- (void) premature;
- Curl_safefree(data->req.p.smb);
- return status;
-}
-
static CURLcode smb_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead)
{
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 6ebb41a..6d0783f4 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -60,11 +60,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -79,6 +74,7 @@
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "select.h"
#include "multiif.h"
@@ -87,6 +83,7 @@
#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
+#include "idn.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -109,7 +106,7 @@ static CURLcode smtp_setup_connection(struct Curl_easy *data,
static CURLcode smtp_parse_url_options(struct connectdata *conn);
static CURLcode smtp_parse_url_path(struct Curl_easy *data);
static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
-static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
+static CURLcode smtp_parse_address(const char *fqma,
char **address, struct hostname *host);
static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
const struct bufref *initresp);
@@ -400,10 +397,15 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
/* Start the SSL connection */
struct connectdata *conn = data->conn;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET,
- &smtpc->ssldone);
+ CURLcode result;
+
+ if(!Curl_conn_is_ssl(data, FIRSTSOCKET)) {
+ result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
+ if(result)
+ goto out;
+ }
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &smtpc->ssldone);
if(!result) {
if(smtpc->state != SMTP_UPGRADETLS)
state(data, SMTP_UPGRADETLS);
@@ -413,7 +415,7 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
result = smtp_perform_ehlo(data);
}
}
-
+out:
return result;
}
@@ -540,7 +542,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
/* Parse the mailbox to verify into the local address and host name
parts, converting the host name to an IDN A-label if necessary */
- result = smtp_parse_address(data, smtp->rcpt->data,
+ result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
return result;
@@ -614,7 +616,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* Parse the FROM mailbox into the local address and host name parts,
converting the host name to an IDN A-label if necessary */
- result = smtp_parse_address(data, data->set.str[STRING_MAIL_FROM],
+ result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
&address, &host);
if(result)
return result;
@@ -652,7 +654,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* Parse the AUTH mailbox into the local address and host name parts,
converting the host name to an IDN A-label if necessary */
- result = smtp_parse_address(data, data->set.str[STRING_MAIL_AUTH],
+ result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
&address, &host);
if(result) {
free(from);
@@ -696,7 +698,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* Add external headers and mime version. */
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
- result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+ result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
NULL, MIMESTRATEGY_MAIL);
if(!result)
@@ -789,7 +791,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
/* Parse the recipient mailbox into the local address and host name parts,
converting the host name to an IDN A-label if necessary */
- result = smtp_parse_address(data, smtp->rcpt->data,
+ result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
return result;
@@ -888,7 +890,8 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
if(smtpcode/100 != 2 && smtpcode != 1) {
- if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
+ if(data->set.use_ssl <= CURLUSESSL_TRY
+ || Curl_conn_is_ssl(data, FIRSTSOCKET))
result = smtp_perform_helo(data, conn);
else {
failf(data, "Remote access denied: %d", smtpcode);
@@ -953,7 +956,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
}
if(smtpcode != 1) {
- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ if(data->set.use_ssl && !Curl_conn_is_ssl(data, FIRSTSOCKET)) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(smtpc->tls_supported)
/* Switch to TLS connection now */
@@ -1043,7 +1046,7 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
}
else {
/* Temporarily add the LF character back and send as body to the client */
- if(!data->set.opt_no_body) {
+ if(!data->req.no_body) {
line[len] = '\n';
result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
line[len] = '\0';
@@ -1285,8 +1288,7 @@ static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done)
struct smtp_conn *smtpc = &conn->proto.smtpc;
if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &smtpc->ssldone);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &smtpc->ssldone);
if(result || !smtpc->ssldone)
return result;
}
@@ -1479,12 +1481,11 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
{
/* This is SMTP and no proxy */
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct SMTP *smtp = data->req.p.smtp;
DEBUGF(infof(data, "DO phase starts"));
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* Requested no body means no transfer */
smtp->transfer = PPTRANSFER_INFO;
}
@@ -1519,7 +1520,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
/* Run the state-machine */
result = smtp_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
@@ -1782,8 +1783,8 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
* calling function deems it to be) then the input will simply be returned in
* the address part with the host name being NULL.
*/
-static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
- char **address, struct hostname *host)
+static CURLcode smtp_parse_address(const char *fqma, char **address,
+ struct hostname *host)
{
CURLcode result = CURLE_OK;
size_t length;
@@ -1807,7 +1808,7 @@ static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
host->name = host->name + 1;
/* Attempt to convert the host name to IDN ACE */
- (void) Curl_idnconvert_hostname(data, host);
+ (void) Curl_idnconvert_hostname(host);
/* If Curl_idnconvert_hostname() fails then we shall attempt to continue
and send the host name using UTF-8 rather than as 7-bit ACE (which is
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index 52c2988..d491e08 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -36,17 +36,52 @@
#include "urldata.h"
#include "sendf.h"
#include "select.h"
+#include "cfilters.h"
#include "connect.h"
#include "timeval.h"
#include "socks.h"
#include "multiif.h" /* for getsock macros */
#include "inet_pton.h"
+#include "url.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
+/* for the (SOCKS) connect state machine */
+enum connect_t {
+ CONNECT_INIT,
+ CONNECT_SOCKS_INIT, /* 1 */
+ CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */
+ CONNECT_SOCKS_READ_INIT, /* 3 set up read */
+ CONNECT_SOCKS_READ, /* 4 read server response */
+ CONNECT_GSSAPI_INIT, /* 5 */
+ CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */
+ CONNECT_AUTH_SEND, /* 7 send auth */
+ CONNECT_AUTH_READ, /* 8 read auth response */
+ CONNECT_REQ_INIT, /* 9 init SOCKS "request" */
+ CONNECT_RESOLVING, /* 10 */
+ CONNECT_RESOLVED, /* 11 */
+ CONNECT_RESOLVE_REMOTE, /* 12 */
+ CONNECT_REQ_SEND, /* 13 */
+ CONNECT_REQ_SENDING, /* 14 */
+ CONNECT_REQ_READ, /* 15 */
+ CONNECT_REQ_READ_MORE, /* 16 */
+ CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */
+};
+
+struct socks_state {
+ enum connect_t state;
+ ssize_t outstanding; /* send this many bytes more */
+ unsigned char *outp; /* send from this pointer */
+
+ const char *hostname;
+ int remote_port;
+ const char *proxy_user;
+ const char *proxy_password;
+};
+
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
* Helper read-from-socket functions. Does the same as Curl_read() but it
@@ -77,7 +112,7 @@ int Curl_blockread_all(struct Curl_easy *data, /* transfer */
result = ~CURLE_OK;
break;
}
- result = Curl_read_plain(sockfd, buf, buffersize, &nread);
+ result = Curl_read_plain(data, sockfd, buf, buffersize, &nread);
if(CURLE_AGAIN == result)
continue;
if(result)
@@ -104,21 +139,20 @@ int Curl_blockread_all(struct Curl_easy *data, /* transfer */
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
#define DEBUG_AND_VERBOSE
-#define sxstate(x,y) socksstate(x,y, __LINE__)
+#define sxstate(x,d,y) socksstate(x,d,y, __LINE__)
#else
-#define sxstate(x,y) socksstate(x,y)
+#define sxstate(x,d,y) socksstate(x,d,y)
#endif
/* always use this function to change state, to make debugging easier */
-static void socksstate(struct Curl_easy *data,
+static void socksstate(struct socks_state *sx, struct Curl_easy *data,
enum connect_t state
#ifdef DEBUG_AND_VERBOSE
, int lineno
#endif
)
{
- struct connectdata *conn = data->conn;
- enum connect_t oldstate = conn->cnnct.state;
+ enum connect_t oldstate = sx->state;
#ifdef DEBUG_AND_VERBOSE
/* synced with the state list in urldata.h */
static const char * const statename[] = {
@@ -143,40 +177,21 @@ static void socksstate(struct Curl_easy *data,
};
#endif
+ (void)data;
if(oldstate == state)
/* don't bother when the new state is the same as the old state */
return;
- conn->cnnct.state = state;
+ sx->state = state;
#ifdef DEBUG_AND_VERBOSE
infof(data,
- "SXSTATE: %s => %s conn %p; line %d",
- statename[oldstate], statename[conn->cnnct.state], conn,
+ "SXSTATE: %s => %s; line %d",
+ statename[oldstate], statename[sx->state],
lineno);
#endif
}
-int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
- int sockindex)
-{
- int rc = 0;
- sock[0] = conn->sock[sockindex];
- switch(conn->cnnct.state) {
- case CONNECT_RESOLVING:
- case CONNECT_SOCKS_READ:
- case CONNECT_AUTH_READ:
- case CONNECT_REQ_READ:
- case CONNECT_REQ_READ_MORE:
- rc = GETSOCK_READSOCK(0);
- break;
- default:
- rc = GETSOCK_WRITESOCK(0);
- break;
- }
- return rc;
-}
-
/*
* This function logs in to a SOCKS4 proxy and sends the specifics to the final
* destination server.
@@ -188,20 +203,16 @@ int Curl_SOCKS_getsock(struct connectdata *conn, curl_socket_t *sock,
* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
* Nonsupport "Identification Protocol (RFC1413)"
*/
-CURLproxycode Curl_SOCKS4(const char *proxy_user,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct Curl_easy *data,
- bool *done)
+static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
+ struct socks_state *sx,
+ struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
+ struct connectdata *conn = cf->conn;
const bool protocol4a =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
unsigned char *socksreq = (unsigned char *)data->state.buffer;
CURLcode result;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct connstate *sx = &conn->cnnct;
+ curl_socket_t sockfd = conn->sock[cf->sockindex];
struct Curl_dns_entry *dns = NULL;
ssize_t actualread;
ssize_t written;
@@ -209,18 +220,16 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
/* make sure that the buffer is at least 600 bytes */
DEBUGASSERT(READBUFFER_MIN >= 600);
- if(!SOCKS_STATE(sx->state) && !*done)
- sxstate(data, CONNECT_SOCKS_INIT);
-
switch(sx->state) {
case CONNECT_SOCKS_INIT:
/* SOCKS4 can only do IPv4, insist! */
conn->ip_version = CURL_IPRESOLVE_V4;
if(conn->bits.httpproxy)
infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d",
- protocol4a ? "a" : "", hostname, remote_port);
+ protocol4a ? "a" : "", sx->hostname, sx->remote_port);
- infof(data, "SOCKS4 communication to %s:%d", hostname, remote_port);
+ infof(data, "SOCKS4 communication to %s:%d",
+ sx->hostname, sx->remote_port);
/*
* Compose socks4 request
@@ -235,40 +244,40 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
socksreq[0] = 4; /* version (SOCKS4) */
socksreq[1] = 1; /* connect */
- socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
- socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
+ socksreq[2] = (unsigned char)((sx->remote_port >> 8) & 0xff); /* MSB */
+ socksreq[3] = (unsigned char)(sx->remote_port & 0xff); /* LSB */
/* DNS resolve only for SOCKS4, not SOCKS4a */
if(!protocol4a) {
enum resolve_t rc =
- Curl_resolv(data, hostname, remote_port, FALSE, &dns);
+ Curl_resolv(data, sx->hostname, sx->remote_port, FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
return CURLPX_RESOLVE_HOST;
else if(rc == CURLRESOLV_PENDING) {
- sxstate(data, CONNECT_RESOLVING);
- infof(data, "SOCKS4 non-blocking resolve of %s", hostname);
+ sxstate(sx, data, CONNECT_RESOLVING);
+ infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname);
return CURLPX_OK;
}
- sxstate(data, CONNECT_RESOLVED);
+ sxstate(sx, data, CONNECT_RESOLVED);
goto CONNECT_RESOLVED;
}
/* socks4a doesn't resolve anything locally */
- sxstate(data, CONNECT_REQ_INIT);
+ sxstate(sx, data, CONNECT_REQ_INIT);
goto CONNECT_REQ_INIT;
case CONNECT_RESOLVING:
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(data, hostname, (int)conn->port);
+ dns = Curl_fetch_addr(data, sx->hostname, (int)conn->port);
if(dns) {
#ifdef CURLRES_ASYNCH
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
- infof(data, "Hostname '%s' was found", hostname);
- sxstate(data, CONNECT_RESOLVED);
+ infof(data, "Hostname '%s' was found", sx->hostname);
+ sxstate(sx, data, CONNECT_RESOLVED);
}
else {
result = Curl_resolv_check(data, &dns);
@@ -309,11 +318,11 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
Curl_resolv_unlock(data, dns); /* not used anymore from now on */
}
else
- failf(data, "SOCKS4 connection to %s not supported", hostname);
+ failf(data, "SOCKS4 connection to %s not supported", sx->hostname);
}
else
failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
- hostname);
+ sx->hostname);
if(!hp)
return CURLPX_RESOLVE_HOST;
@@ -325,14 +334,14 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
* This is currently not supporting "Identification Protocol (RFC1413)".
*/
socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
- if(proxy_user) {
- size_t plen = strlen(proxy_user);
+ if(sx->proxy_user) {
+ size_t plen = strlen(sx->proxy_user);
if(plen >= (size_t)data->set.buffer_size - 8) {
failf(data, "Too long SOCKS proxy user name, can't use");
return CURLPX_LONG_USER;
}
/* copy the proxy name WITH trailing zero */
- memcpy(socksreq + 8, proxy_user, plen + 1);
+ memcpy(socksreq + 8, sx->proxy_user, plen + 1);
}
/*
@@ -350,9 +359,9 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
socksreq[6] = 0;
socksreq[7] = 1;
/* append hostname */
- hostnamelen = strlen(hostname) + 1; /* length including NUL */
+ hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
if(hostnamelen <= 255)
- strcpy((char *)socksreq + packetsize, hostname);
+ strcpy((char *)socksreq + packetsize, sx->hostname);
else {
failf(data, "SOCKS4: too long host name");
return CURLPX_LONG_HOSTNAME;
@@ -361,7 +370,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
}
sx->outp = socksreq;
sx->outstanding = packetsize;
- sxstate(data, CONNECT_REQ_SENDING);
+ sxstate(sx, data, CONNECT_REQ_SENDING);
}
/* FALLTHROUGH */
case CONNECT_REQ_SENDING:
@@ -382,12 +391,12 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
/* done sending! */
sx->outstanding = 8; /* receive data size */
sx->outp = socksreq;
- sxstate(data, CONNECT_SOCKS_READ);
+ sxstate(sx, data, CONNECT_SOCKS_READ);
/* FALLTHROUGH */
case CONNECT_SOCKS_READ:
/* Receive response */
- result = Curl_read_plain(sockfd, (char *)sx->outp,
+ result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "SOCKS4: Failed receiving connect request ack: %s",
@@ -405,7 +414,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
sx->outp += actualread;
return CURLPX_OK;
}
- sxstate(data, CONNECT_DONE);
+ sxstate(sx, data, CONNECT_DONE);
break;
default: /* lots of unused states in SOCKS4 */
break;
@@ -478,7 +487,6 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
return CURLPX_UNKNOWN_FAIL;
}
- *done = TRUE;
return CURLPX_OK; /* Proxy was successful! */
}
@@ -486,13 +494,9 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
* This function logs in to a SOCKS5 proxy and sends the specifics to the final
* destination server.
*/
-CURLproxycode Curl_SOCKS5(const char *proxy_user,
- const char *proxy_password,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct Curl_easy *data,
- bool *done)
+static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
+ struct socks_state *sx,
+ struct Curl_easy *data)
{
/*
According to the RFC1928, section "6. Replies". This is what a SOCK5
@@ -510,31 +514,28 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
o REP Reply field:
o X'00' succeeded
*/
- struct connectdata *conn = data->conn;
+ struct connectdata *conn = cf->conn;
unsigned char *socksreq = (unsigned char *)data->state.buffer;
char dest[256] = "unknown"; /* printable hostname:port */
int idx;
ssize_t actualread;
ssize_t written;
CURLcode result;
- curl_socket_t sockfd = conn->sock[sockindex];
+ curl_socket_t sockfd = conn->sock[cf->sockindex];
bool socks5_resolve_local =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
- const size_t hostname_len = strlen(hostname);
+ const size_t hostname_len = strlen(sx->hostname);
ssize_t len = 0;
- const unsigned long auth = data->set.socks5auth;
+ const unsigned char auth = data->set.socks5auth;
bool allow_gssapi = FALSE;
- struct connstate *sx = &conn->cnnct;
struct Curl_dns_entry *dns = NULL;
- if(!SOCKS_STATE(sx->state) && !*done)
- sxstate(data, CONNECT_SOCKS_INIT);
-
+ DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI));
switch(sx->state) {
case CONNECT_SOCKS_INIT:
if(conn->bits.httpproxy)
infof(data, "SOCKS5: connecting to HTTP proxy %s port %d",
- hostname, remote_port);
+ sx->hostname, sx->remote_port);
/* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
if(!socks5_resolve_local && hostname_len > 255) {
@@ -545,11 +546,11 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
infof(data,
- "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu",
+ "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u",
auth);
if(!(auth & CURLAUTH_BASIC))
/* disable username/password auth */
- proxy_user = NULL;
+ sx->proxy_user = NULL;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
if(auth & CURLAUTH_GSSAPI)
allow_gssapi = TRUE;
@@ -561,23 +562,23 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
socksreq[idx++] = 0; /* no authentication */
if(allow_gssapi)
socksreq[idx++] = 1; /* GSS-API */
- if(proxy_user)
+ if(sx->proxy_user)
socksreq[idx++] = 2; /* username/password */
/* write the number of authentication methods */
socksreq[1] = (unsigned char) (idx - 2);
- result = Curl_write_plain(data, sockfd, (char *)socksreq, idx, &written);
+ result = Curl_write_plain(data, sockfd, socksreq, idx, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to send initial SOCKS5 request.");
return CURLPX_SEND_CONNECT;
}
if(written != idx) {
- sxstate(data, CONNECT_SOCKS_SEND);
+ sxstate(sx, data, CONNECT_SOCKS_SEND);
sx->outstanding = idx - written;
sx->outp = &socksreq[written];
return CURLPX_OK;
}
- sxstate(data, CONNECT_SOCKS_READ);
+ sxstate(sx, data, CONNECT_SOCKS_READ);
goto CONNECT_SOCKS_READ_INIT;
case CONNECT_SOCKS_SEND:
result = Curl_write_plain(data, sockfd, (char *)sx->outp,
@@ -599,7 +600,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
sx->outp = socksreq; /* store it here */
/* FALLTHROUGH */
case CONNECT_SOCKS_READ:
- result = Curl_read_plain(sockfd, (char *)sx->outp,
+ result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive initial SOCKS5 response.");
@@ -622,18 +623,18 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
}
else if(socksreq[1] == 0) {
/* DONE! No authentication needed. Send request. */
- sxstate(data, CONNECT_REQ_INIT);
+ sxstate(sx, data, CONNECT_REQ_INIT);
goto CONNECT_REQ_INIT;
}
else if(socksreq[1] == 2) {
/* regular name + password authentication */
- sxstate(data, CONNECT_AUTH_INIT);
+ sxstate(sx, data, CONNECT_AUTH_INIT);
goto CONNECT_AUTH_INIT;
}
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
else if(allow_gssapi && (socksreq[1] == 1)) {
- sxstate(data, CONNECT_GSSAPI_INIT);
- result = Curl_SOCKS5_gssapi_negotiate(sockindex, data);
+ sxstate(sx, data, CONNECT_GSSAPI_INIT);
+ result = Curl_SOCKS5_gssapi_negotiate(cf->sockindex, data);
if(result) {
failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
return CURLPX_GSSAPI;
@@ -668,9 +669,9 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
case CONNECT_AUTH_INIT: {
/* Needs user name and password */
size_t proxy_user_len, proxy_password_len;
- if(proxy_user && proxy_password) {
- proxy_user_len = strlen(proxy_user);
- proxy_password_len = strlen(proxy_password);
+ if(sx->proxy_user && sx->proxy_password) {
+ proxy_user_len = strlen(sx->proxy_user);
+ proxy_password_len = strlen(sx->proxy_password);
}
else {
proxy_user_len = 0;
@@ -687,32 +688,32 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
len = 0;
socksreq[len++] = 1; /* username/pw subnegotiation version */
socksreq[len++] = (unsigned char) proxy_user_len;
- if(proxy_user && proxy_user_len) {
+ if(sx->proxy_user && proxy_user_len) {
/* the length must fit in a single byte */
- if(proxy_user_len >= 255) {
+ if(proxy_user_len > 255) {
failf(data, "Excessive user name length for proxy auth");
return CURLPX_LONG_USER;
}
- memcpy(socksreq + len, proxy_user, proxy_user_len);
+ memcpy(socksreq + len, sx->proxy_user, proxy_user_len);
}
len += proxy_user_len;
socksreq[len++] = (unsigned char) proxy_password_len;
- if(proxy_password && proxy_password_len) {
+ if(sx->proxy_password && proxy_password_len) {
/* the length must fit in a single byte */
if(proxy_password_len > 255) {
failf(data, "Excessive password length for proxy auth");
return CURLPX_LONG_PASSWD;
}
- memcpy(socksreq + len, proxy_password, proxy_password_len);
+ memcpy(socksreq + len, sx->proxy_password, proxy_password_len);
}
len += proxy_password_len;
- sxstate(data, CONNECT_AUTH_SEND);
+ sxstate(sx, data, CONNECT_AUTH_SEND);
sx->outstanding = len;
sx->outp = socksreq;
}
/* FALLTHROUGH */
case CONNECT_AUTH_SEND:
- result = Curl_write_plain(data, sockfd, (char *)sx->outp,
+ result = Curl_write_plain(data, sockfd, sx->outp,
sx->outstanding, &written);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to send SOCKS5 sub-negotiation request.");
@@ -726,10 +727,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
}
sx->outp = socksreq;
sx->outstanding = 2;
- sxstate(data, CONNECT_AUTH_READ);
+ sxstate(sx, data, CONNECT_AUTH_READ);
/* FALLTHROUGH */
case CONNECT_AUTH_READ:
- result = Curl_read_plain(sockfd, (char *)sx->outp,
+ result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
@@ -754,36 +755,36 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
}
/* Everything is good so far, user was authenticated! */
- sxstate(data, CONNECT_REQ_INIT);
+ sxstate(sx, data, CONNECT_REQ_INIT);
/* FALLTHROUGH */
CONNECT_REQ_INIT:
case CONNECT_REQ_INIT:
if(socks5_resolve_local) {
- enum resolve_t rc = Curl_resolv(data, hostname, remote_port,
+ enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port,
FALSE, &dns);
if(rc == CURLRESOLV_ERROR)
return CURLPX_RESOLVE_HOST;
if(rc == CURLRESOLV_PENDING) {
- sxstate(data, CONNECT_RESOLVING);
+ sxstate(sx, data, CONNECT_RESOLVING);
return CURLPX_OK;
}
- sxstate(data, CONNECT_RESOLVED);
+ sxstate(sx, data, CONNECT_RESOLVED);
goto CONNECT_RESOLVED;
}
goto CONNECT_RESOLVE_REMOTE;
case CONNECT_RESOLVING:
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(data, hostname, remote_port);
+ dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port);
if(dns) {
#ifdef CURLRES_ASYNCH
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
- infof(data, "SOCKS5: hostname '%s' found", hostname);
+ infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
}
if(!dns) {
@@ -803,13 +804,13 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
hp = dns->addr;
if(!hp) {
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
- hostname);
+ sx->hostname);
return CURLPX_RESOLVE_HOST;
}
Curl_printable_address(hp, dest, sizeof(dest));
destlen = strlen(dest);
- msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port);
+ msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", sx->remote_port);
len = 0;
socksreq[len++] = 5; /* version (SOCKS5) */
@@ -866,7 +867,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip) {
char ip6[16];
- if(1 != Curl_inet_pton(AF_INET6, hostname, ip6))
+ if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6))
return CURLPX_BAD_ADDRESS_TYPE;
socksreq[len++] = 4;
memcpy(&socksreq[len], ip6, sizeof(ip6));
@@ -874,7 +875,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
}
else
#endif
- if(1 == Curl_inet_pton(AF_INET, hostname, ip4)) {
+ if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) {
socksreq[len++] = 1;
memcpy(&socksreq[len], ip4, sizeof(ip4));
len += sizeof(ip4);
@@ -882,20 +883,20 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
else {
socksreq[len++] = 3;
socksreq[len++] = (char) hostname_len; /* one byte address length */
- memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
+ memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */
len += hostname_len;
}
infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
- hostname, remote_port);
+ sx->hostname, sx->remote_port);
}
/* FALLTHROUGH */
CONNECT_REQ_SEND:
case CONNECT_REQ_SEND:
/* PORT MSB */
- socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff);
+ socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff);
/* PORT LSB */
- socksreq[len++] = (unsigned char)(remote_port & 0xff);
+ socksreq[len++] = (unsigned char)(sx->remote_port & 0xff);
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
if(conn->socks5_gssapi_enctype) {
@@ -905,7 +906,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
#endif
sx->outp = socksreq;
sx->outstanding = len;
- sxstate(data, CONNECT_REQ_SENDING);
+ sxstate(sx, data, CONNECT_REQ_SENDING);
/* FALLTHROUGH */
case CONNECT_REQ_SENDING:
result = Curl_write_plain(data, sockfd, (char *)sx->outp,
@@ -928,10 +929,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
#endif
sx->outstanding = 10; /* minimum packet size is 10 */
sx->outp = socksreq;
- sxstate(data, CONNECT_REQ_READ);
+ sxstate(sx, data, CONNECT_REQ_READ);
/* FALLTHROUGH */
case CONNECT_REQ_READ:
- result = Curl_read_plain(sockfd, (char *)sx->outp,
+ result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
@@ -958,7 +959,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
int code = socksreq[1];
failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
- hostname, (unsigned char)socksreq[1]);
+ sx->hostname, (unsigned char)socksreq[1]);
if(code < 9) {
/* RFC 1928 section 6 lists: */
static const CURLproxycode lookup[] = {
@@ -1019,10 +1020,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
if(len > 10) {
sx->outstanding = len - 10; /* get the rest */
sx->outp = &socksreq[10];
- sxstate(data, CONNECT_REQ_READ_MORE);
+ sxstate(sx, data, CONNECT_REQ_READ_MORE);
}
else {
- sxstate(data, CONNECT_DONE);
+ sxstate(sx, data, CONNECT_DONE);
break;
}
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@@ -1030,7 +1031,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
#endif
/* FALLTHROUGH */
case CONNECT_REQ_READ_MORE:
- result = Curl_read_plain(sockfd, (char *)sx->outp,
+ result = Curl_read_plain(data, sockfd, (char *)sx->outp,
sx->outstanding, &actualread);
if(result && (CURLE_AGAIN != result)) {
failf(data, "Failed to receive SOCKS5 connect request ack.");
@@ -1047,12 +1048,214 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
sx->outp += actualread;
return CURLPX_OK;
}
- sxstate(data, CONNECT_DONE);
+ sxstate(sx, data, CONNECT_DONE);
}
infof(data, "SOCKS5 request granted.");
- *done = TRUE;
return CURLPX_OK; /* Proxy was successful! */
}
+static CURLcode connect_SOCKS(struct Curl_cfilter *cf,
+ struct socks_state *sxstate,
+ struct Curl_easy *data)
+{
+ CURLcode result = CURLE_OK;
+ CURLproxycode pxresult = CURLPX_OK;
+ struct connectdata *conn = cf->conn;
+
+ switch(conn->socks_proxy.proxytype) {
+ case CURLPROXY_SOCKS5:
+ case CURLPROXY_SOCKS5_HOSTNAME:
+ pxresult = do_SOCKS5(cf, sxstate, data);
+ break;
+
+ case CURLPROXY_SOCKS4:
+ case CURLPROXY_SOCKS4A:
+ pxresult = do_SOCKS4(cf, sxstate, data);
+ break;
+
+ default:
+ failf(data, "unknown proxytype option given");
+ result = CURLE_COULDNT_CONNECT;
+ } /* switch proxytype */
+ if(pxresult) {
+ result = CURLE_PROXY;
+ data->info.pxcode = pxresult;
+ }
+
+ return result;
+}
+
+static void socks_proxy_cf_free(struct Curl_cfilter *cf)
+{
+ struct socks_state *sxstate = cf->ctx;
+ if(sxstate) {
+ free(sxstate);
+ cf->ctx = NULL;
+ }
+}
+
+/* After a TCP connection to the proxy has been verified, this function does
+ the next magic steps. If 'done' isn't set TRUE, it is not done yet and
+ must be called again.
+
+ Note: this function's sub-functions call failf()
+
+*/
+static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ CURLcode result;
+ struct connectdata *conn = cf->conn;
+ int sockindex = cf->sockindex;
+ struct socks_state *sx = cf->ctx;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ result = cf->next->cft->connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ return result;
+
+ if(!sx) {
+ sx = calloc(sizeof(*sx), 1);
+ if(!sx)
+ return CURLE_OUT_OF_MEMORY;
+ cf->ctx = sx;
+ }
+
+ if(sx->state == CONNECT_INIT) {
+ /* for the secondary socket (FTP), use the "connect to host"
+ * but ignore the "connect to port" (use the secondary port)
+ */
+ sxstate(sx, data, CONNECT_SOCKS_INIT);
+ sx->hostname =
+ conn->bits.httpproxy ?
+ conn->http_proxy.host.name :
+ conn->bits.conn_to_host ?
+ conn->conn_to_host.name :
+ sockindex == SECONDARYSOCKET ?
+ conn->secondaryhostname : conn->host.name;
+ sx->remote_port =
+ conn->bits.httpproxy ? (int)conn->http_proxy.port :
+ sockindex == SECONDARYSOCKET ? conn->secondary_port :
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port;
+ sx->proxy_user = conn->socks_proxy.user;
+ sx->proxy_password = conn->socks_proxy.passwd;
+ }
+
+ result = connect_SOCKS(cf, sx, data);
+ if(!result && sx->state == CONNECT_DONE) {
+ cf->connected = TRUE;
+ Curl_updateconninfo(data, conn, conn->sock[cf->sockindex]);
+ Curl_verboseconnect(data, conn);
+ socks_proxy_cf_free(cf);
+ }
+
+ *done = cf->connected;
+ return result;
+}
+
+static int socks_cf_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ struct socks_state *sx = cf->ctx;
+ int fds;
+
+ fds = cf->next->cft->get_select_socks(cf->next, data, socks);
+ if(!fds && cf->next->connected && !cf->connected && sx) {
+ /* If we are not connected, the filter below is and has nothing
+ * to wait on, we determine what to wait for. */
+ socks[0] = cf->conn->sock[cf->sockindex];
+ switch(sx->state) {
+ case CONNECT_RESOLVING:
+ case CONNECT_SOCKS_READ:
+ case CONNECT_AUTH_READ:
+ case CONNECT_REQ_READ:
+ case CONNECT_REQ_READ_MORE:
+ fds = GETSOCK_READSOCK(0);
+ break;
+ default:
+ fds = GETSOCK_WRITESOCK(0);
+ break;
+ }
+ }
+ return fds;
+}
+
+static void socks_proxy_cf_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+
+ DEBUGASSERT(cf->next);
+ cf->connected = FALSE;
+ socks_proxy_cf_free(cf);
+ cf->next->cft->close(cf->next, data);
+}
+
+static void socks_proxy_cf_destroy(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ (void)data;
+ socks_proxy_cf_free(cf);
+}
+
+static void socks_proxy_cf_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ (void)data;
+ socks_proxy_cf_free(cf);
+}
+
+static void socks_cf_get_host(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char **phost,
+ const char **pdisplay_host,
+ int *pport)
+{
+ (void)data;
+ if(!cf->connected) {
+ *phost = cf->conn->socks_proxy.host.name;
+ *pdisplay_host = cf->conn->http_proxy.host.dispname;
+ *pport = (int)cf->conn->socks_proxy.port;
+ }
+ else {
+ cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
+ }
+}
+
+static const struct Curl_cftype cft_socks_proxy = {
+ "SOCKS-PROXYY",
+ CF_TYPE_IP_CONNECT,
+ socks_proxy_cf_destroy,
+ Curl_cf_def_setup,
+ socks_proxy_cf_connect,
+ socks_proxy_cf_close,
+ socks_cf_get_host,
+ socks_cf_get_select_socks,
+ Curl_cf_def_data_pending,
+ Curl_cf_def_send,
+ Curl_cf_def_recv,
+ Curl_cf_def_attach_data,
+ socks_proxy_cf_detach_data,
+};
+
+CURLcode Curl_conn_socks_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+ CURLcode result;
+
+ result = Curl_cf_create(&cf, &cft_socks_proxy, NULL);
+ if(!result)
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+ return result;
+}
+
#endif /* CURL_DISABLE_PROXY */
diff --git a/Utilities/cmcurl/lib/socks.h b/Utilities/cmcurl/lib/socks.h
index ff83aa5..2e2fa18 100644
--- a/Utilities/cmcurl/lib/socks.h
+++ b/Utilities/cmcurl/lib/socks.h
@@ -43,32 +43,6 @@ int Curl_blockread_all(struct Curl_easy *data,
ssize_t buffersize,
ssize_t *n);
-int Curl_SOCKS_getsock(struct connectdata *conn,
- curl_socket_t *sock,
- int sockindex);
-/*
- * This function logs in to a SOCKS4(a) proxy and sends the specifics to the
- * final destination server.
- */
-CURLproxycode Curl_SOCKS4(const char *proxy_name,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct Curl_easy *data,
- bool *done);
-
-/*
- * This function logs in to a SOCKS5 proxy and sends the specifics to the
- * final destination server.
- */
-CURLproxycode Curl_SOCKS5(const char *proxy_name,
- const char *proxy_password,
- const char *hostname,
- int remote_port,
- int sockindex,
- struct Curl_easy *data,
- bool *done);
-
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
* This function handles the SOCKS5 GSS-API negotiation and initialization
@@ -77,6 +51,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
struct Curl_easy *data);
#endif
+CURLcode Curl_conn_socks_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
#endif /* CURL_DISABLE_PROXY */
#endif /* HEADER_CURL_SOCKS_H */
diff --git a/Utilities/cmcurl/lib/strcase.c b/Utilities/cmcurl/lib/strcase.c
index 09d2a8a..7fb9c80 100644
--- a/Utilities/cmcurl/lib/strcase.c
+++ b/Utilities/cmcurl/lib/strcase.c
@@ -83,16 +83,13 @@ char Curl_raw_tolower(char in)
}
/*
- * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is
- * meant to be locale independent and only compare strings we know are safe
- * for this. See
- * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
- * further explanation to why this function is necessary.
- *
- * @unittest: 1301
+ * curl_strequal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * further explanations as to why this function is necessary.
*/
-int Curl_strcasecompare(const char *first, const char *second)
+static int casecompare(const char *first, const char *second)
{
while(*first && *second) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
@@ -108,25 +105,22 @@ int Curl_strcasecompare(const char *first, const char *second)
return !*first == !*second;
}
-int Curl_safe_strcasecompare(const char *first, const char *second)
+/* --- public function --- */
+int curl_strequal(const char *first, const char *second)
{
if(first && second)
/* both pointers point to something then compare them */
- return Curl_strcasecompare(first, second);
+ return casecompare(first, second);
/* if both pointers are NULL then treat them as equal */
return (NULL == first && NULL == second);
}
-/*
- * @unittest: 1301
- */
-int Curl_strncasecompare(const char *first, const char *second, size_t max)
+static int ncasecompare(const char *first, const char *second, size_t max)
{
while(*first && *second && max) {
- if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
- break;
- }
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+ return 0;
max--;
first++;
second++;
@@ -137,6 +131,16 @@ int Curl_strncasecompare(const char *first, const char *second, size_t max)
return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
}
+/* --- public function --- */
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+ if(first && second)
+ /* both pointers point to something then compare them */
+ return ncasecompare(first, second, max);
+
+ /* if both pointers are NULL then treat them as equal if max is non-zero */
+ return (NULL == first && NULL == second && max);
+}
/* Copy an upper case version of the string from src to dest. The
* strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be
@@ -198,14 +202,3 @@ int Curl_timestrcmp(const char *a, const char *b)
return a || b;
return match;
}
-
-/* --- public functions --- */
-
-int curl_strequal(const char *first, const char *second)
-{
- return Curl_strcasecompare(first, second);
-}
-int curl_strnequal(const char *first, const char *second, size_t max)
-{
- return Curl_strncasecompare(first, second, max);
-}
diff --git a/Utilities/cmcurl/lib/strcase.h b/Utilities/cmcurl/lib/strcase.h
index 65a5753..192e0da 100644
--- a/Utilities/cmcurl/lib/strcase.h
+++ b/Utilities/cmcurl/lib/strcase.h
@@ -35,12 +35,8 @@
* Result is 1 if text matches and 0 if not.
*/
-#define strcasecompare(a,b) Curl_strcasecompare(a,b)
-#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c)
-
-int Curl_strcasecompare(const char *first, const char *second);
-int Curl_safe_strcasecompare(const char *first, const char *second);
-int Curl_strncasecompare(const char *first, const char *second, size_t max);
+#define strcasecompare(a,b) curl_strequal(a,b)
+#define strncasecompare(a,b,c) curl_strnequal(a,b,c)
char Curl_raw_toupper(char in);
char Curl_raw_tolower(char in);
diff --git a/Utilities/cmcurl/lib/strtoofft.c b/Utilities/cmcurl/lib/strtoofft.c
index 30deb8c..fb8d921 100644
--- a/Utilities/cmcurl/lib/strtoofft.c
+++ b/Utilities/cmcurl/lib/strtoofft.c
@@ -221,6 +221,7 @@ CURLofft curlx_strtoofft(const char *str, char **endp, int base,
curl_off_t number;
errno = 0;
*num = 0; /* clear by default */
+ DEBUGASSERT(base); /* starting now, avoid base zero */
while(*str && ISBLANK(*str))
str++;
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index 923c7f8..22bc81e 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -571,7 +571,7 @@ void rec_do(struct Curl_easy *data, int option)
sendsuboption(data, option);
}
else if(tn->subnegotiation[option] == CURL_YES) {
- /* send information to achieve this option*/
+ /* send information to achieve this option */
tn->us[option] = CURL_YES;
send_negotiation(data, CURL_WILL, option);
sendsuboption(data, option);
@@ -1200,7 +1200,7 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
j = 0;
for(i = 0; i < nread; i++) {
- outbuf[j++] = buffer[i];
+ outbuf[j++] = (unsigned char)buffer[i];
if((unsigned char)buffer[i] == CURL_IAC)
outbuf[j++] = CURL_IAC;
}
@@ -1248,9 +1248,6 @@ static CURLcode telnet_done(struct Curl_easy *data,
curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL;
-
- Curl_safefree(data->req.p.telnet);
-
return CURLE_OK;
}
@@ -1491,6 +1488,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
while(keepon) {
+ DEBUGF(infof(data, "telnet_do(handle=%p), poll %d fds", data, poll_cnt));
switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
case -1: /* error, stop reading */
keepon = FALSE;
@@ -1509,6 +1507,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
/* returned not-zero, this an error */
if(result) {
keepon = FALSE;
+ /* TODO: in test 1452, macOS sees a ECONNRESET sometimes?
+ * Is this the telnet test server not shutting down the socket
+ * in a clean way? Seems to be timing related, happens more
+ * on slow debug build */
+ if(data->state.os_errno == ECONNRESET) {
+ DEBUGF(infof(data, "telnet_do(handle=%p), unexpected ECONNRESET"
+ " on recv", data));
+ }
break;
}
/* returned zero but actually received 0 or less here,
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 441da73..ba0410f 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -64,6 +64,7 @@
#include "content_encoding.h"
#include "hostip.h"
+#include "cfilters.h"
#include "transfer.h"
#include "sendf.h"
#include "speedcheck.h"
@@ -362,89 +363,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
return CURLE_OK;
}
-
-/*
- * Curl_readrewind() rewinds the read stream. This is typically used for HTTP
- * POST/PUT with multi-pass authentication when a sending was denied and a
- * resend is necessary.
- */
-CURLcode Curl_readrewind(struct Curl_easy *data)
-{
- struct connectdata *conn = data->conn;
- curl_mimepart *mimepart = &data->set.mimepost;
-
- conn->bits.rewindaftersend = FALSE; /* we rewind now */
-
- /* explicitly switch off sending data on this connection now since we are
- about to restart a new transfer and thus we want to avoid inadvertently
- sending more data on the existing connection until the next transfer
- starts */
- data->req.keepon &= ~KEEP_SEND;
-
- /* We have sent away data. If not using CURLOPT_POSTFIELDS or
- CURLOPT_HTTPPOST, call app to rewind
- */
- if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
- struct HTTP *http = data->req.p.http;
-
- if(http->sendit)
- mimepart = http->sendit;
- }
- if(data->set.postfields)
- ; /* do nothing */
- else if(data->state.httpreq == HTTPREQ_POST_MIME ||
- data->state.httpreq == HTTPREQ_POST_FORM) {
- CURLcode result = Curl_mime_rewind(mimepart);
- if(result) {
- failf(data, "Cannot rewind mime/post data");
- return result;
- }
- }
- else {
- if(data->set.seek_func) {
- int err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
- Curl_set_in_callback(data, false);
- if(err) {
- failf(data, "seek callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else if(data->set.ioctl_func) {
- curlioerr err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
- data->set.ioctl_client);
- Curl_set_in_callback(data, false);
- infof(data, "the ioctl callback returned %d", (int)err);
-
- if(err) {
- failf(data, "ioctl callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else {
- /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
- given FILE * stream and we can actually attempt to rewind that
- ourselves with fseek() */
- if(data->state.fread_func == (curl_read_callback)fread) {
- if(-1 != fseek(data->state.in, 0, SEEK_SET))
- /* successful rewind */
- return CURLE_OK;
- }
-
- /* no callback set or failure above, makes us fail at once */
- failf(data, "necessary data rewind wasn't possible");
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- return CURLE_OK;
-}
-
-static int data_pending(const struct Curl_easy *data)
+static int data_pending(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
@@ -454,7 +373,7 @@ static int data_pending(const struct Curl_easy *data)
#endif
if(conn->handler->protocol&PROTO_FAMILY_FTP)
- return Curl_ssl_data_pending(conn, SECONDARYSOCKET);
+ return Curl_conn_data_pending(data, SECONDARYSOCKET);
/* in the case of libssh2, we can never be really sure that we have emptied
its internal buffers so we MUST always try until we get EAGAIN back */
@@ -469,7 +388,7 @@ static int data_pending(const struct Curl_easy *data)
a workaround, we return nonzero here to call http2_recv. */
((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20) ||
#endif
- Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ Curl_conn_data_pending(data, FIRSTSOCKET);
}
/*
@@ -569,11 +488,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread);
/* read would've blocked */
- if(CURLE_AGAIN == result)
+ if(CURLE_AGAIN == result) {
+ result = CURLE_OK;
break; /* get out of loop */
+ }
if(result>0)
- return result;
+ goto out;
}
else {
/* read nothing but since we wanted nothing we consider this an OK
@@ -619,7 +540,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(conn->handler->readwrite) {
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
break;
}
@@ -632,13 +553,13 @@ static CURLcode readwrite_data(struct Curl_easy *data,
bool stop_reading = FALSE;
result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
if(result)
- return result;
+ goto out;
if(conn->handler->readwrite &&
(k->maxdownload <= 0 && nread > 0)) {
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
break;
}
@@ -665,11 +586,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
is non-headers. */
if(!k->header && (nread > 0 || is_empty_data)) {
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
/* data arrives although we want none, bail out */
streamclose(conn, "ignoring body");
*done = TRUE;
- return CURLE_WEIRD_SERVER_REPLY;
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto out;
}
#ifndef CURL_DISABLE_HTTP
@@ -680,7 +602,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* HTTP-only checks */
result = Curl_http_firstwrite(data, conn, done);
if(result || *done)
- return result;
+ goto out;
}
} /* this is the first time we write a body part */
#endif /* CURL_DISABLE_HTTP */
@@ -717,10 +639,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(CHUNKE_OK < res) {
if(CHUNKE_PASSTHRU_ERROR == res) {
failf(data, "Failed reading the chunked-encoded stream");
- return extra;
+ result = extra;
+ goto out;
}
failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res));
- return CURLE_RECV_ERROR;
+ result = CURLE_RECV_ERROR;
+ goto out;
}
if(CHUNKE_STOP == res) {
/* we're done reading chunks! */
@@ -796,7 +720,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
(size_t)k->maxdownload);
if(result)
- return result;
+ goto out;
}
if(k->badheader < HEADER_ALLBAD) {
/* This switch handles various content encodings. If there's an
@@ -821,7 +745,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->badheader = HEADER_NORMAL; /* taken care of now */
if(result)
- return result;
+ goto out;
}
} /* if(!header and data to read) */
@@ -839,7 +763,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
result = conn->handler->readwrite(data, conn, &nread, &readmore);
if(result)
- return result;
+ goto out;
if(readmore)
k->keepon |= KEEP_RECV; /* we're not done reading */
@@ -874,7 +798,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
}
- return CURLE_OK;
+out:
+ DEBUGF(infof(data, "readwrite_data(handle=%p) -> %d", data, result));
+ return result;
}
CURLcode Curl_done_sending(struct Curl_easy *data,
@@ -887,11 +813,6 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
Curl_http2_done_sending(data, conn);
Curl_quic_done_sending(data);
- if(conn->bits.rewindaftersend) {
- CURLcode result = Curl_readrewind(data);
- if(result)
- return result;
- }
return CURLE_OK;
}
@@ -1201,14 +1122,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(select_res == CURL_CSELECT_ERR) {
failf(data, "select/poll returned error");
- return CURLE_SEND_ERROR;
+ result = CURLE_SEND_ERROR;
+ goto out;
}
#ifdef USE_HYPER
if(conn->datastream) {
result = conn->datastream(data, conn, &didwhat, done, select_res);
if(result || *done)
- return result;
+ goto out;
}
else {
#endif
@@ -1218,7 +1140,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if((k->keepon & KEEP_RECV) && (select_res & CURL_CSELECT_IN)) {
result = readwrite_data(data, conn, k, &didwhat, done, comeback);
if(result || *done)
- return result;
+ goto out;
}
/* If we still have writing to do, we check if we have a writable socket. */
@@ -1227,7 +1149,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
result = readwrite_upload(data, conn, &didwhat);
if(result)
- return result;
+ goto out;
}
#ifdef USE_HYPER
}
@@ -1264,7 +1186,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(conn->transport == TRNSPRT_QUIC) {
result = Curl_quic_idle(data);
if(result)
- return result;
+ goto out;
}
#endif
}
@@ -1274,7 +1196,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
else
result = Curl_speedcheck(data, k->now);
if(result)
- return result;
+ goto out;
if(k->keepon) {
if(0 > Curl_timeleft(data, &k->now, FALSE)) {
@@ -1291,7 +1213,8 @@ CURLcode Curl_readwrite(struct connectdata *conn,
Curl_timediff(k->now, data->progress.t_startsingle),
k->bytecount);
}
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
}
else {
@@ -1300,7 +1223,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* returning.
*/
- if(!(data->set.opt_no_body) && (k->size != -1) &&
+ if(!(data->req.no_body) && (k->size != -1) &&
(k->bytecount != k->size) &&
#ifdef CURL_DO_LINEEND_CONV
/* Most FTP servers don't adjust their file SIZE response for CRLFs,
@@ -1312,9 +1235,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
!k->newurl) {
failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
" bytes remaining to read", k->size - k->bytecount);
- return CURLE_PARTIAL_FILE;
+ result = CURLE_PARTIAL_FILE;
+ goto out;
}
- if(!(data->set.opt_no_body) && k->chunk &&
+ if(!(data->req.no_body) && k->chunk &&
(conn->chunk.state != CHUNK_STOP)) {
/*
* In chunked mode, return an error if the connection is closed prior to
@@ -1326,17 +1250,22 @@ CURLcode Curl_readwrite(struct connectdata *conn,
*
*/
failf(data, "transfer closed with outstanding read data remaining");
- return CURLE_PARTIAL_FILE;
+ result = CURLE_PARTIAL_FILE;
+ goto out;
+ }
+ if(Curl_pgrsUpdate(data)) {
+ result = CURLE_ABORTED_BY_CALLBACK;
+ goto out;
}
- if(Curl_pgrsUpdate(data))
- return CURLE_ABORTED_BY_CALLBACK;
}
/* Now update the "done" boolean we return */
*done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
-
- return CURLE_OK;
+ result = CURLE_OK;
+out:
+ DEBUGF(infof(data, "Curl_readwrite(handle=%p) -> %d", data, result));
+ return result;
}
/*
@@ -1367,7 +1296,6 @@ int Curl_single_getsock(struct Curl_easy *data,
/* don't include HOLD and PAUSE connections */
if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
-
if((conn->sockfd != conn->writesockfd) ||
bitmap == GETSOCK_BLANK) {
/* only if they are not the same socket and we have a readable
@@ -1511,7 +1439,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
- * basically anything through a http proxy we can't limit this based on
+ * basically anything through an HTTP proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
@@ -1591,10 +1519,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
to URL */
}
else {
- /* mark the next request as a followed location: */
- data->state.this_is_a_follow = TRUE;
-
- data->state.followlocation++; /* count location-followers */
+ data->state.followlocation++; /* count redirect-followings, including
+ auth reloads */
if(data->set.http_auto_referer) {
CURLU *u;
@@ -1743,7 +1669,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
* differently based on exactly what return code there was.
*
* News from 7.10.6: we can also get here on a 401 or 407, in case we act on
- * a HTTP (proxy-) authentication scheme other than Basic.
+ * an HTTP (proxy-) authentication scheme other than Basic.
*/
switch(data->info.httpcode) {
/* 401 - Act on a WWW-Authenticate, we keep on moving and do the
@@ -1823,7 +1749,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
data->state.httpreq = HTTPREQ_GET;
data->set.upload = false;
infof(data, "Switch to %s",
- data->set.opt_no_body?"HEAD":"GET");
+ data->req.no_body?"HEAD":"GET");
}
break;
case 304: /* Not Modified */
@@ -1865,7 +1791,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
if((data->req.bytecount + data->req.headerbytecount == 0) &&
conn->bits.reuse &&
- (!data->set.opt_no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
+ (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
#ifndef CURL_DISABLE_RTSP
&& (data->set.rtspreq != RTSPREQ_RECEIVE)
#endif
@@ -1911,14 +1837,10 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
transferred! */
- if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
- if(data->req.writebytecount) {
- CURLcode result = Curl_readrewind(data);
- if(result) {
- Curl_safefree(*url);
- return result;
- }
- }
+ if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ data->req.writebytecount) {
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "state.rewindbeforesend = TRUE");
}
}
return CURLE_OK;
@@ -1979,7 +1901,7 @@ Curl_setup_transfer(
Curl_pgrsSetDownloadSize(data, size);
}
/* we want header and/or body, if neither then don't do this! */
- if(k->getheader || !data->set.opt_no_body) {
+ if(k->getheader || !data->req.no_body) {
if(sockindex != -1)
k->keepon |= KEEP_RECV;
@@ -2015,6 +1937,6 @@ Curl_setup_transfer(
k->keepon |= KEEP_SEND;
}
} /* if(writesockindex != -1) */
- } /* if(k->getheader || !data->set.opt_no_body) */
+ } /* if(k->getheader || !data->req.no_body) */
}
diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h
index 65fe68e..4092508 100644
--- a/Utilities/cmcurl/lib/transfer.h
+++ b/Utilities/cmcurl/lib/transfer.h
@@ -50,7 +50,6 @@ CURLcode Curl_readwrite(struct connectdata *conn,
bool *comeback);
int Curl_single_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
-CURLcode Curl_readrewind(struct Curl_easy *data);
CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
size_t *nreadp);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index be5ffca..3ab63a0 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -61,26 +61,9 @@
#include <limits.h>
-#ifdef USE_LIBIDN2
-#include <idn2.h>
-
-#if defined(WIN32) && defined(UNICODE)
-#define IDN2_LOOKUP(name, host, flags) \
- idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
-#else
-#define IDN2_LOOKUP(name, host, flags) \
- idn2_lookup_ul((const char *)name, (char **)host, flags)
-#endif
-
-#elif defined(USE_WIN32_IDN)
-/* prototype for Curl_win32_idn_to_ascii() */
-bool Curl_win32_idn_to_ascii(const char *in, char **out);
-#endif /* USE_LIBIDN2 */
-
#include "doh.h"
#include "urldata.h"
#include "netrc.h"
-
#include "formdata.h"
#include "mime.h"
#include "vtls/vtls.h"
@@ -107,6 +90,8 @@ bool Curl_win32_idn_to_ascii(const char *in, char **out);
#include "system_win32.h"
#include "hsts.h"
#include "noproxy.h"
+#include "cfilters.h"
+#include "idn.h"
/* And now for the protocols */
#include "ftp.h"
@@ -140,7 +125,11 @@ bool Curl_win32_idn_to_ascii(const char *in, char **out);
#include "curl_memory.h"
#include "memdebug.h"
-static void conn_free(struct connectdata *conn);
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+static void conn_free(struct Curl_easy *data, struct connectdata *conn);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
* more than just a few bytes to play with. Don't let it become too small or
@@ -539,6 +528,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
/* Set the default size of the SSL session ID cache */
set->general_ssl.max_ssl_sessions = 5;
+ /* Timeout every 24 hours by default */
+ set->general_ssl.ca_cache_timeout = 24 * 60 * 60;
set->proxyport = 0;
set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
@@ -553,7 +544,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
/* make libcurl quiet by default: */
set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
- Curl_mime_initpart(&set->mimepost, data);
+ Curl_mime_initpart(&set->mimepost);
/*
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
@@ -648,6 +639,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
#endif
;
Curl_http2_init_userset(set);
+ set->quick_exit = 0L;
return result;
}
@@ -745,37 +737,28 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
-static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
+static void conn_shutdown(struct Curl_easy *data)
{
- DEBUGASSERT(conn);
DEBUGASSERT(data);
- infof(data, "Closing connection %ld", conn->connection_id);
+ infof(data, "Closing connection %ld", data->conn->connection_id);
/* possible left-overs from the async name resolvers */
Curl_resolver_cancel(data);
- /* close the SSL stuff before we close any sockets since they will/may
- write to the sockets */
- Curl_ssl_close(data, conn, FIRSTSOCKET);
-#ifndef CURL_DISABLE_FTP
- Curl_ssl_close(data, conn, SECONDARYSOCKET);
-#endif
-
- /* close possibly still open sockets */
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
- if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
- Curl_closesocket(data, conn, conn->sock[FIRSTSOCKET]);
- if(CURL_SOCKET_BAD != conn->tempsock[0])
- Curl_closesocket(data, conn, conn->tempsock[0]);
- if(CURL_SOCKET_BAD != conn->tempsock[1])
- Curl_closesocket(data, conn, conn->tempsock[1]);
+ Curl_conn_close(data, SECONDARYSOCKET);
+ Curl_conn_close(data, FIRSTSOCKET);
}
-static void conn_free(struct connectdata *conn)
+static void conn_free(struct Curl_easy *data, struct connectdata *conn)
{
+ size_t i;
+
DEBUGASSERT(conn);
+ for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
+ Curl_conn_cf_discard_all(data, conn, (int)i);
+ }
+
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY
@@ -799,7 +782,6 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
- Curl_safefree(conn->connect_state);
conn_reset_all_postponed_data(conn);
Curl_llist_destroy(&conn->easyq, NULL);
@@ -810,9 +792,6 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->unix_domain_socket);
#endif
-#ifdef USE_SSL
- Curl_safefree(conn->ssl_extra);
-#endif
free(conn); /* free all the connection oriented data */
}
@@ -845,6 +824,8 @@ void Curl_disconnect(struct Curl_easy *data,
/* the transfer must be detached from the connection */
DEBUGASSERT(!data->conn);
+ DEBUGF(infof(data, "Curl_disconnect(conn #%ld, dead=%d)",
+ conn->connection_id, dead_connection));
/*
* If this connection isn't marked to force-close, leave it open if there
* are other users of it
@@ -877,12 +858,12 @@ void Curl_disconnect(struct Curl_easy *data,
/* This is set if protocol-specific cleanups should be made */
conn->handler->disconnect(data, conn, dead_connection);
- conn_shutdown(data, conn);
+ conn_shutdown(data);
/* detach it again */
Curl_detach_connection(data);
- conn_free(conn);
+ conn_free(data, conn);
}
/*
@@ -914,7 +895,7 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle,
{
int avail = 0;
- /* If a HTTP protocol and multiplexing is enabled */
+ /* If an HTTP protocol and multiplexing is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(!conn->bits.protoconnstart || !conn->bits.close)) {
@@ -933,7 +914,7 @@ proxy_info_matches(const struct proxy_info *data,
{
if((data->proxytype == needle->proxytype) &&
(data->port == needle->port) &&
- Curl_safe_strcasecompare(data->host.name, needle->host.name))
+ strcasecompare(data->host.name, needle->host.name))
return TRUE;
return FALSE;
@@ -1197,7 +1178,7 @@ ConnectionExists(struct Curl_easy *data,
size_t multiplexed = 0;
/*
- * Note that if we use a HTTP proxy in normal mode (no tunneling), we
+ * Note that if we use an HTTP proxy in normal mode (no tunneling), we
* check connections to that proxy and not to the actual remote server.
*/
check = curr->ptr;
@@ -1240,7 +1221,7 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
+ if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
foundPendingCandidate = TRUE;
/* Don't pick a connection that hasn't connected yet */
infof(data, "Connection #%ld isn't open enough, can't reuse",
@@ -1306,15 +1287,11 @@ ConnectionExists(struct Curl_easy *data,
if(!Curl_ssl_config_matches(&needle->proxy_ssl_config,
&check->proxy_ssl_config))
continue;
- if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
- continue;
}
if(!Curl_ssl_config_matches(&needle->ssl_config,
&check->ssl_config))
continue;
- if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete)
- continue;
}
}
#endif
@@ -1381,9 +1358,9 @@ ConnectionExists(struct Curl_easy *data,
|| !needle->bits.httpproxy || needle->bits.tunnel_proxy
#endif
) {
- /* The requested connection does not use a HTTP proxy or it uses SSL or
- it is a non-SSL protocol tunneled or it is a non-SSL protocol which
- is allowed to be upgraded via TLS */
+ /* The requested connection does not use an HTTP proxy or it uses SSL
+ or it is a non-SSL protocol tunneled or it is a non-SSL protocol
+ which is allowed to be upgraded via TLS */
if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
(get_protocol_family(check->handler) ==
@@ -1408,14 +1385,6 @@ ConnectionExists(struct Curl_easy *data,
check->connection_id));
continue;
}
- if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
- foundPendingCandidate = TRUE;
- DEBUGF(infof(data,
- "Connection #%ld has not started SSL connect, "
- "can't reuse",
- check->connection_id));
- continue;
- }
}
match = TRUE;
}
@@ -1566,111 +1535,6 @@ void Curl_verboseconnect(struct Curl_easy *data,
#endif
/*
- * Helpers for IDNA conversions.
- */
-bool Curl_is_ASCII_name(const char *hostname)
-{
- /* get an UNSIGNED local version of the pointer */
- const unsigned char *ch = (const unsigned char *)hostname;
-
- if(!hostname) /* bad input, consider it ASCII! */
- return TRUE;
-
- while(*ch) {
- if(*ch++ & 0x80)
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Perform any necessary IDN conversion of hostname
- */
-CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
- struct hostname *host)
-{
-#ifndef USE_LIBIDN2
- (void)data;
- (void)data;
-#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
- (void)data;
-#endif
-
- /* set the name we use to display the host name */
- host->dispname = host->name;
-
- /* Check name for non-ASCII and convert hostname to ACE form if we can */
- if(!Curl_is_ASCII_name(host->name)) {
-#ifdef USE_LIBIDN2
- if(idn2_check_version(IDN2_VERSION)) {
- char *ace_hostname = NULL;
-#if IDN2_VERSION_NUMBER >= 0x00140000
- /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
- IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
- processing. */
- int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL;
-#else
- int flags = IDN2_NFC_INPUT;
-#endif
- int rc = IDN2_LOOKUP(host->name, &ace_hostname, flags);
- if(rc != IDN2_OK)
- /* fallback to TR46 Transitional mode for better IDNA2003
- compatibility */
- rc = IDN2_LOOKUP(host->name, &ace_hostname,
- IDN2_TRANSITIONAL);
- if(rc == IDN2_OK) {
- host->encalloc = (char *)ace_hostname;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
- }
- else {
- failf(data, "Failed to convert %s to ACE; %s", host->name,
- idn2_strerror(rc));
- return CURLE_URL_MALFORMAT;
- }
- }
-#elif defined(USE_WIN32_IDN)
- char *ace_hostname = NULL;
-
- if(Curl_win32_idn_to_ascii(host->name, &ace_hostname)) {
- host->encalloc = ace_hostname;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
- }
- else {
- char buffer[STRERROR_LEN];
- failf(data, "Failed to convert %s to ACE; %s", host->name,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
- return CURLE_URL_MALFORMAT;
- }
-#else
- infof(data, "IDN support not present, can't parse Unicode domains");
-#endif
- }
- return CURLE_OK;
-}
-
-/*
- * Frees data allocated by idnconvert_hostname()
- */
-void Curl_free_idnconverted_hostname(struct hostname *host)
-{
-#if defined(USE_LIBIDN2)
- if(host->encalloc) {
- idn2_free(host->encalloc); /* must be freed with idn2_free() since this was
- allocated by libidn */
- host->encalloc = NULL;
- }
-#elif defined(USE_WIN32_IDN)
- free(host->encalloc); /* must be freed with free() since this was
- allocated by Curl_win32_idn_to_ascii */
- host->encalloc = NULL;
-#else
- (void)host;
-#endif
-}
-
-/*
* Allocate and initialize a new connectdata object.
*/
static struct connectdata *allocate_conn(struct Curl_easy *data)
@@ -1679,45 +1543,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
if(!conn)
return NULL;
-#ifdef USE_SSL
- /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
- a separate array to ensure suitable alignment.
- Note that these backend pointers can be swapped by vtls (eg ssl backend
- data becomes proxy backend data). */
- {
- size_t onesize = Curl_ssl->sizeof_ssl_backend_data;
- size_t totalsize = onesize;
- char *ssl;
-
-#ifndef CURL_DISABLE_FTP
- totalsize *= 2;
-#endif
-#ifndef CURL_DISABLE_PROXY
- totalsize *= 2;
-#endif
-
- ssl = calloc(1, totalsize);
- if(!ssl) {
- free(conn);
- return NULL;
- }
- conn->ssl_extra = ssl;
- conn->ssl[FIRSTSOCKET].backend = (void *)ssl;
-#ifndef CURL_DISABLE_FTP
- ssl += onesize;
- conn->ssl[SECONDARYSOCKET].backend = (void *)ssl;
-#endif
-#ifndef CURL_DISABLE_PROXY
- ssl += onesize;
- conn->proxy_ssl[FIRSTSOCKET].backend = (void *)ssl;
-#ifndef CURL_DISABLE_FTP
- ssl += onesize;
- conn->proxy_ssl[SECONDARYSOCKET].backend = (void *)ssl;
-#endif
-#endif
- }
-#endif
-
conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
already from start to avoid NULL
situations and checks */
@@ -1825,9 +1650,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
Curl_llist_destroy(&conn->easyq, NULL);
free(conn->localdev);
-#ifdef USE_SSL
- free(conn->ssl_extra);
-#endif
free(conn);
return NULL;
}
@@ -2051,26 +1873,14 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
/*************************************************************
* IDN-convert the hostnames
*************************************************************/
- result = Curl_idnconvert_hostname(data, &conn->host);
+ result = Curl_idnconvert_hostname(&conn->host);
if(result)
return result;
if(conn->bits.conn_to_host) {
- result = Curl_idnconvert_hostname(data, &conn->conn_to_host);
- if(result)
- return result;
- }
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.httpproxy) {
- result = Curl_idnconvert_hostname(data, &conn->http_proxy.host);
- if(result)
- return result;
- }
- if(conn->bits.socksproxy) {
- result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host);
+ result = Curl_idnconvert_hostname(&conn->conn_to_host);
if(result)
return result;
}
-#endif
#ifndef CURL_DISABLE_HSTS
/* HSTS upgrade */
@@ -2433,7 +2243,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
}
#ifdef USE_SSL
- if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
+ if(!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY))
#endif
if(proxytype == CURLPROXY_HTTPS) {
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
@@ -2449,7 +2259,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
proxytype == CURLPROXY_SOCKS4;
proxyinfo = sockstype ? &conn->socks_proxy : &conn->http_proxy;
- proxyinfo->proxytype = proxytype;
+ proxyinfo->proxytype = (unsigned char)proxytype;
/* Is there a username and password given in this proxy url? */
uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
@@ -2704,7 +2514,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
if(conn->http_proxy.host.rawalloc) {
#ifdef CURL_DISABLE_HTTP
- /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
+ /* asking for an HTTP proxy is a bit funny when HTTP is disabled... */
result = CURLE_UNSUPPORTED_PROTOCOL;
goto out;
#else
@@ -2721,7 +2531,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
#endif
}
else {
- conn->bits.httpproxy = FALSE; /* not a HTTP proxy */
+ conn->bits.httpproxy = FALSE; /* not an HTTP proxy */
conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
}
@@ -3527,13 +3337,13 @@ static CURLcode resolve_server(struct Curl_easy *data,
}
/*
- * Cleanup the connection just allocated before we can move along and use the
- * previously existing one. All relevant data is copied over and old_conn is
- * ready for freeing once this function returns.
+ * Cleanup the connection `temp`, just allocated for `data`, before using the
+ * previously `existing` one for `data`. All relevant info is copied over
+ * and `temp` is freed.
*/
static void reuse_conn(struct Curl_easy *data,
- struct connectdata *old_conn,
- struct connectdata *conn)
+ struct connectdata *temp,
+ struct connectdata *existing)
{
/* 'local_ip' and 'local_port' get filled with local's numerical
ip address and port number whenever an outgoing connection is
@@ -3541,66 +3351,66 @@ static void reuse_conn(struct Curl_easy *data,
char local_ip[MAX_IPADR_LEN] = "";
int local_port = -1;
- /* get the user+password information from the old_conn struct since it may
+ /* get the user+password information from the temp struct since it may
* be new for this request even when we re-use an existing connection */
- if(old_conn->user) {
+ if(temp->user) {
/* use the new user name and password though */
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- conn->user = old_conn->user;
- conn->passwd = old_conn->passwd;
- old_conn->user = NULL;
- old_conn->passwd = NULL;
+ Curl_safefree(existing->user);
+ Curl_safefree(existing->passwd);
+ existing->user = temp->user;
+ existing->passwd = temp->passwd;
+ temp->user = NULL;
+ temp->passwd = NULL;
}
#ifndef CURL_DISABLE_PROXY
- conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
- if(conn->bits.proxy_user_passwd) {
+ existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
+ if(existing->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
- Curl_safefree(conn->http_proxy.user);
- Curl_safefree(conn->socks_proxy.user);
- Curl_safefree(conn->http_proxy.passwd);
- Curl_safefree(conn->socks_proxy.passwd);
- conn->http_proxy.user = old_conn->http_proxy.user;
- conn->socks_proxy.user = old_conn->socks_proxy.user;
- conn->http_proxy.passwd = old_conn->http_proxy.passwd;
- conn->socks_proxy.passwd = old_conn->socks_proxy.passwd;
- old_conn->http_proxy.user = NULL;
- old_conn->socks_proxy.user = NULL;
- old_conn->http_proxy.passwd = NULL;
- old_conn->socks_proxy.passwd = NULL;
- }
-#endif
-
- Curl_free_idnconverted_hostname(&conn->host);
- Curl_free_idnconverted_hostname(&conn->conn_to_host);
- Curl_safefree(conn->host.rawalloc);
- Curl_safefree(conn->conn_to_host.rawalloc);
- conn->host = old_conn->host;
- old_conn->host.rawalloc = NULL;
- old_conn->host.encalloc = NULL;
- conn->conn_to_host = old_conn->conn_to_host;
- old_conn->conn_to_host.rawalloc = NULL;
- conn->conn_to_port = old_conn->conn_to_port;
- conn->remote_port = old_conn->remote_port;
- Curl_safefree(conn->hostname_resolve);
-
- conn->hostname_resolve = old_conn->hostname_resolve;
- old_conn->hostname_resolve = NULL;
+ Curl_safefree(existing->http_proxy.user);
+ Curl_safefree(existing->socks_proxy.user);
+ Curl_safefree(existing->http_proxy.passwd);
+ Curl_safefree(existing->socks_proxy.passwd);
+ existing->http_proxy.user = temp->http_proxy.user;
+ existing->socks_proxy.user = temp->socks_proxy.user;
+ existing->http_proxy.passwd = temp->http_proxy.passwd;
+ existing->socks_proxy.passwd = temp->socks_proxy.passwd;
+ temp->http_proxy.user = NULL;
+ temp->socks_proxy.user = NULL;
+ temp->http_proxy.passwd = NULL;
+ temp->socks_proxy.passwd = NULL;
+ }
+#endif
+
+ Curl_free_idnconverted_hostname(&existing->host);
+ Curl_free_idnconverted_hostname(&existing->conn_to_host);
+ Curl_safefree(existing->host.rawalloc);
+ Curl_safefree(existing->conn_to_host.rawalloc);
+ existing->host = temp->host;
+ temp->host.rawalloc = NULL;
+ temp->host.encalloc = NULL;
+ existing->conn_to_host = temp->conn_to_host;
+ temp->conn_to_host.rawalloc = NULL;
+ existing->conn_to_port = temp->conn_to_port;
+ existing->remote_port = temp->remote_port;
+ Curl_safefree(existing->hostname_resolve);
+
+ existing->hostname_resolve = temp->hostname_resolve;
+ temp->hostname_resolve = NULL;
/* persist connection info in session handle */
- if(conn->transport == TRNSPRT_TCP) {
- Curl_conninfo_local(data, conn->sock[FIRSTSOCKET],
+ if(existing->transport == TRNSPRT_TCP) {
+ Curl_conninfo_local(data, existing->sock[FIRSTSOCKET],
local_ip, &local_port);
}
- Curl_persistconninfo(data, conn, local_ip, local_port);
+ Curl_persistconninfo(data, existing, local_ip, local_port);
- conn_reset_all_postponed_data(old_conn); /* free buffers */
+ conn_reset_all_postponed_data(temp); /* free buffers */
/* re-use init */
- conn->bits.reuse = TRUE; /* yes, we're re-using here */
+ existing->bits.reuse = TRUE; /* yes, we're re-using here */
- conn_free(old_conn);
+ conn_free(data, temp);
}
/**
@@ -3624,7 +3434,7 @@ static CURLcode create_conn(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct connectdata *conn;
- struct connectdata *conn_temp = NULL;
+ struct connectdata *existing = NULL;
bool reuse;
bool connections_available = TRUE;
bool force_reuse = FALSE;
@@ -3730,6 +3540,21 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
+ /*************************************************************
+ * IDN-convert the proxy hostnames
+ *************************************************************/
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.httpproxy) {
+ result = Curl_idnconvert_hostname(&conn->http_proxy.host);
+ if(result)
+ return result;
+ }
+ if(conn->bits.socksproxy) {
+ result = Curl_idnconvert_hostname(&conn->socks_proxy.host);
+ if(result)
+ return result;
+ }
+#endif
/*************************************************************
* Check whether the host and the "connect to host" are equal.
@@ -3766,13 +3591,6 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- conn->recv[FIRSTSOCKET] = Curl_recv_plain;
- conn->send[FIRSTSOCKET] = Curl_send_plain;
- conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
- conn->send[SECONDARYSOCKET] = Curl_send_plain;
-
- conn->bits.tcp_fastopen = data->set.tcp_fastopen;
-
/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
@@ -3787,8 +3605,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Setup a "faked" transfer that'll do nothing */
if(!result) {
- conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
-
Curl_attach_connection(data, conn);
result = Curl_conncache_add_conn(data);
if(result)
@@ -3814,6 +3630,13 @@ static CURLcode create_conn(struct Curl_easy *data,
}
#endif
+ /* Setup filter for network connections */
+ conn->recv[FIRSTSOCKET] = Curl_conn_recv;
+ conn->send[FIRSTSOCKET] = Curl_conn_send;
+ conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
+ conn->send[SECONDARYSOCKET] = Curl_conn_send;
+ conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
/* Get a cloned copy of the SSL config situation stored in the
connection struct. But to get this going nicely, we must first make
sure that the strings in the master copy are pointing to the correct
@@ -3907,22 +3730,22 @@ static CURLcode create_conn(struct Curl_easy *data,
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
we only acknowledge this option if this is not a re-used connection
- already (which happens due to follow-location or during a HTTP
+ already (which happens due to follow-location or during an HTTP
authentication phase). CONNECT_ONLY transfers also refuse reuse. */
- if((data->set.reuse_fresh && !data->state.this_is_a_follow) ||
+ if((data->set.reuse_fresh && !data->state.followlocation) ||
data->set.connect_only)
reuse = FALSE;
else
- reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
+ reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
if(reuse) {
/*
* We already have a connection for this, we got the former connection in
- * the conn_temp variable and thus we need to cleanup the one we just
- * allocated before we can move along and use the previously existing one.
+ * `existing` and thus we need to cleanup the one we just
+ * allocated before we can move along and use `existing`.
*/
- reuse_conn(data, conn, conn_temp);
- conn = conn_temp;
+ reuse_conn(data, conn, existing);
+ conn = existing;
*in_connect = conn;
#ifndef CURL_DISABLE_PROXY
@@ -3997,7 +3820,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(!connections_available) {
infof(data, "No connections available.");
- conn_free(conn);
+ conn_free(data, conn);
*in_connect = NULL;
result = CURLE_NO_CONNECTION_AVAILABLE;
@@ -4080,7 +3903,6 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
*protocol_done = TRUE;
return result;
}
- *protocol_done = FALSE; /* default to not done */
#ifndef CURL_DISABLE_PROXY
/* set proxy_connect_closed to false unconditionally already here since it
@@ -4097,26 +3919,11 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
/* set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
conn->now = Curl_now();
-
- if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
- conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
- result = Curl_connecthost(data, conn, conn->dns_entry);
- if(result)
- return result;
- }
- else {
- Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- if(conn->ssl[FIRSTSOCKET].use ||
- (conn->handler->protocol & PROTO_FAMILY_SSH))
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
- conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
- *protocol_done = TRUE;
- Curl_updateconninfo(data, conn, conn->sock[FIRSTSOCKET]);
- Curl_verboseconnect(data, conn);
- }
-
- conn->now = Curl_now(); /* time this *after* the connect is done, we set
- this here perhaps a second time */
+ if(!conn->bits.reuse)
+ result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
+ CURL_CF_SSL_DEFAULT);
+ /* not sure we need this flag to be passed around any more */
+ *protocol_done = FALSE;
return result;
}
@@ -4133,6 +3940,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
Curl_free_request_state(data);
memset(&data->req, 0, sizeof(struct SingleRequest));
data->req.size = data->req.maxdownload = -1;
+ data->req.no_body = data->set.opt_no_body;
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
@@ -4194,7 +4002,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
- if(data->set.opt_no_body)
+ if(data->req.no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->state.httpreq = HTTPREQ_HEAD;
diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h
index ba4270d..1a03c56 100644
--- a/Utilities/cmcurl/lib/url.h
+++ b/Utilities/cmcurl/lib/url.h
@@ -49,11 +49,6 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
size_t schemelen);
-bool Curl_is_ASCII_name(const char *hostname);
-CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
- struct hostname *host);
-void Curl_free_idnconverted_hostname(struct hostname *host);
-
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
specified */
@@ -64,21 +59,4 @@ void Curl_free_idnconverted_hostname(struct hostname *host);
void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn);
#endif
-#ifdef CURL_DISABLE_PROXY
-#define CONNECT_PROXY_SSL() FALSE
-#else
-
-#define CONNECT_PROXY_SSL()\
- (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
- !conn->bits.proxy_ssl_connected[sockindex])
-
-#define CONNECT_FIRSTSOCKET_PROXY_SSL()\
- (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
- !conn->bits.proxy_ssl_connected[FIRSTSOCKET])
-
-#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\
- (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
- !conn->bits.proxy_ssl_connected[SECONDARYSOCKET])
-#endif /* !CURL_DISABLE_PROXY */
-
#endif /* HEADER_CURL_URL_H */
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 7dac81c..b96af35 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -636,7 +636,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
}
else {
/* letters from the second string are not ok */
- len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,");
+ len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()");
if(hlen != len)
/* hostname with bad content */
return CURLUE_BAD_HOSTNAME;
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 1d430b5..3d7545c 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -113,6 +113,24 @@ typedef unsigned int curl_prot_t;
input easier and better. */
#define CURL_MAX_INPUT_LENGTH 8000000
+/* Macros intended for DEBUGF logging, use like:
+ * DEBUGF(infof(data, CFMSG(cf, "this filter %s rocks"), "very much"));
+ * and it will output:
+ * [CONN-1-0][CF-SSL] this filter very much rocks
+ * on connection #1 with sockindex 0 for filter of type "SSL". */
+#define DMSG(d,msg) \
+ "[CONN-%ld] "msg, (d)->conn->connection_id
+#define DMSGI(d,i,msg) \
+ "[CONN-%ld-%d] "msg, (d)->conn->connection_id, (i)
+#define CMSG(c,msg) \
+ "[CONN-%ld] "msg, (conn)->connection_id
+#define CMSGI(c,i,msg) \
+ "[CONN-%ld-%d] "msg, (conn)->connection_id, (i)
+#define CFMSG(cf,msg) \
+ "[CONN-%ld-%d][CF-%s] "msg, (cf)->conn->connection_id, \
+ (cf)->sockindex, (cf)->cft->name
+
+
#include "cookie.h"
#include "psl.h"
#include "formdata.h"
@@ -249,22 +267,9 @@ typedef enum {
/* SSL backend-specific data; declared differently by each SSL backend */
struct ssl_backend_data;
-/* struct for data related to each SSL connection */
-struct ssl_connect_data {
- ssl_connection_state state;
- ssl_connect_state connecting_state;
-#if defined(USE_SSL)
- struct ssl_backend_data *backend;
-#endif
- /* Use ssl encrypted communications TRUE/FALSE. The library is not
- necessarily using ssl at the moment but at least asked to or means to use
- it. See 'state' for the exact current state of the connection. */
- BIT(use);
-};
-
struct ssl_primary_config {
long version; /* what version the client wants to use */
- long version_max; /* max supported version the client wants to use*/
+ long version_max; /* max supported version the client wants to use */
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
char *issuercert; /* optional issuer certificate filename */
@@ -301,7 +306,7 @@ struct ssl_config_data {
char *key_passwd; /* plain text private key password */
BIT(certinfo); /* gather lots of certificate info */
BIT(falsestart);
- BIT(enable_beast); /* allow this flaw for interoperability's sake*/
+ BIT(enable_beast); /* allow this flaw for interoperability's sake */
BIT(no_revoke); /* disable SSL certificate revocation checks */
BIT(no_partialchain); /* don't accept partial certificate chains */
BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
@@ -313,6 +318,7 @@ struct ssl_config_data {
struct ssl_general_config {
size_t max_ssl_sessions; /* SSL session id cache size */
+ int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
};
/* information stored about one single SSL session */
@@ -476,12 +482,8 @@ struct negotiatedata {
* Boolean values that concerns this connection.
*/
struct ConnectBits {
- bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
- the first time on the first connect function call */
#ifndef CURL_DISABLE_PROXY
- bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy
- is complete */
- BIT(httpproxy); /* if set, this transfer is done through a http proxy */
+ BIT(httpproxy); /* if set, this transfer is done through an HTTP proxy */
BIT(socksproxy); /* if set, this transfer is done through a socks proxy */
BIT(proxy_user_passwd); /* user+password for the proxy? */
BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy.
@@ -514,10 +516,6 @@ struct ConnectBits {
that we are creating a request with an auth header,
but it is not the final request in the auth
negotiation. */
- BIT(rewindaftersend);/* TRUE when the sending couldn't be stopped even
- though it will be discarded. When the whole send
- operation is done, we must call the data rewind
- callback. */
#ifndef CURL_DISABLE_FTP
BIT(ftp_use_epsv); /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
EPSV doesn't work we disable it for the forthcoming
@@ -724,6 +722,7 @@ struct SingleRequest {
BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in http.c
for details. */
+ BIT(no_body); /* the response has no body */
};
/*
@@ -865,7 +864,7 @@ struct postponed_data {
struct proxy_info {
struct hostname host;
- long port;
+ int port;
unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in
use */
char *user; /* proxy user name string, allocated */
@@ -873,38 +872,6 @@ struct proxy_info {
};
struct ldapconninfo;
-struct http_connect_state;
-
-/* for the (SOCKS) connect state machine */
-enum connect_t {
- CONNECT_INIT,
- CONNECT_SOCKS_INIT, /* 1 */
- CONNECT_SOCKS_SEND, /* 2 waiting to send more first data */
- CONNECT_SOCKS_READ_INIT, /* 3 set up read */
- CONNECT_SOCKS_READ, /* 4 read server response */
- CONNECT_GSSAPI_INIT, /* 5 */
- CONNECT_AUTH_INIT, /* 6 setup outgoing auth buffer */
- CONNECT_AUTH_SEND, /* 7 send auth */
- CONNECT_AUTH_READ, /* 8 read auth response */
- CONNECT_REQ_INIT, /* 9 init SOCKS "request" */
- CONNECT_RESOLVING, /* 10 */
- CONNECT_RESOLVED, /* 11 */
- CONNECT_RESOLVE_REMOTE, /* 12 */
- CONNECT_REQ_SEND, /* 13 */
- CONNECT_REQ_SENDING, /* 14 */
- CONNECT_REQ_READ, /* 15 */
- CONNECT_REQ_READ_MORE, /* 16 */
- CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */
-};
-
-#define SOCKS_STATE(x) (((x) >= CONNECT_SOCKS_INIT) && \
- ((x) < CONNECT_DONE))
-
-struct connstate {
- enum connect_t state;
- ssize_t outstanding; /* send this many bytes more */
- unsigned char *outp; /* send from this pointer */
-};
#define TRNSPRT_TCP 3
#define TRNSPRT_UDP 4
@@ -916,12 +883,11 @@ struct connstate {
* unique for an entire connection.
*/
struct connectdata {
- struct connstate cnnct;
struct Curl_llist_element bundle_node; /* conncache */
/* chunk is for HTTP chunked encoding, but is in the general connectdata
- struct only because we can do just about any protocol through a HTTP proxy
- and a HTTP proxy may in fact respond using chunked encoding */
+ struct only because we can do just about any protocol through an HTTP
+ proxy and an HTTP proxy may in fact respond using chunked encoding */
struct Curl_chunker chunk;
curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
@@ -985,17 +951,11 @@ struct connectdata {
int tempfamily[2]; /* family used for the temp sockets */
Curl_recv *recv[2];
Curl_send *send[2];
+ struct Curl_cfilter *cfilter[2]; /* connection filters */
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
struct postponed_data postponed[2]; /* two buffers for two sockets */
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
- struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
-#ifndef CURL_DISABLE_PROXY
- struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */
-#endif
-#ifdef USE_SSL
- void *ssl_extra; /* separately allocated backend-specific data */
-#endif
struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
struct ssl_primary_config proxy_ssl_config;
@@ -1112,7 +1072,6 @@ struct connectdata {
#endif
} proto;
- struct http_connect_state *connect_state; /* for HTTP CONNECT */
struct connectbundle *bundle; /* The bundle we are member of */
#ifdef USE_UNIX_SOCKETS
char *unix_domain_socket;
@@ -1520,6 +1479,9 @@ struct UrlState {
BIT(url_alloc); /* URL string is malloc()'ed */
BIT(referer_alloc); /* referer string is malloc()ed */
BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */
+ BIT(rewindbeforesend);/* TRUE when the sending couldn't be stopped even
+ though it will be discarded. We must call the data
+ rewind callback before trying to send again. */
};
/*
@@ -1531,7 +1493,7 @@ struct UrlState {
* Character pointer fields point to dynamic storage, unless otherwise stated.
*/
-struct Curl_multi; /* declared and used only in multi.c */
+struct Curl_multi; /* declared in multihandle.c */
/*
* This enumeration MUST not use conditional directives (#ifdefs), new
@@ -1655,17 +1617,17 @@ struct UserDefined {
FILE *err; /* the stderr user data goes here */
void *debugdata; /* the data that will be passed to fdebug */
char *errorbuffer; /* (Static) store failure messages in here */
- long proxyport; /* If non-zero, use this port number by default. If the
- proxy string features a ":[port]" that one will override
- this. */
void *out; /* CURLOPT_WRITEDATA */
void *in_set; /* CURLOPT_READDATA */
void *writeheader; /* write the header to this if non-NULL */
+ unsigned short proxyport; /* If non-zero, use this port number by
+ default. If the proxy string features a
+ ":[port]" that one will override this. */
unsigned short use_port; /* which port to use (when not using default) */
unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */
unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */
#ifndef CURL_DISABLE_PROXY
- unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */
+ unsigned char socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */
#endif
long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
for infinity */
@@ -1859,8 +1821,12 @@ struct UserDefined {
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */
+ BIT(quick_exit); /* set 1L when it is okay to leak things (like
+ threads), as we're about to exit() anyway and
+ don't want lengthy cleanups to delay termination,
+ e.g. after a DNS timeout */
BIT(get_filetime); /* get the time and get of the remote file */
- BIT(tunnel_thru_httpproxy); /* use CONNECT through a HTTP proxy */
+ BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
BIT(prefer_ascii); /* ASCII rather than binary */
BIT(remote_append); /* append, not overwrite, on upload */
BIT(list_only); /* list directory */
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index f945e8b..c81ce10 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -142,7 +142,7 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
}
#if !defined(USE_WINDOWS_SSPI)
-/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string */
static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
unsigned char *dest) /* 33 bytes */
{
@@ -151,7 +151,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
-/* Convert sha256 chunk to RFC7616 -suitable ascii string*/
+/* Convert sha256 chunk to RFC7616 -suitable ascii string */
static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
unsigned char *dest) /* 65 bytes */
{
@@ -186,7 +186,7 @@ static char *auth_digest_string_quoted(const char *source)
}
*d++ = *s++;
}
- *d = 0;
+ *d = '\0';
}
return dest;
@@ -490,7 +490,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/*
* Curl_auth_decode_digest_http_message()
*
- * This is used to decode a HTTP DIGEST challenge message into the separate
+ * This is used to decode an HTTP DIGEST challenge message into the separate
* attributes.
*
* Parameters:
@@ -650,7 +650,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
/*
* auth_create_digest_http_message()
*
- * This is used to generate a HTTP DIGEST response message ready for sending
+ * This is used to generate an HTTP DIGEST response message ready for sending
* to the recipient.
*
* Parameters:
@@ -926,7 +926,7 @@ static CURLcode auth_create_digest_http_message(
/*
* Curl_auth_create_digest_http_message()
*
- * This is used to generate a HTTP DIGEST response message ready for sending
+ * This is used to generate an HTTP DIGEST response message ready for sending
* to the recipient.
*
* Parameters:
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
index 89a9db5..6c95a3e 100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -307,7 +307,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg,
/*
* Curl_auth_decode_digest_http_message()
*
- * This is used to decode a HTTP DIGEST challenge message into the separate
+ * This is used to decode an HTTP DIGEST challenge message into the separate
* attributes.
*
* Parameters:
@@ -371,7 +371,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
/*
* Curl_auth_create_digest_http_message()
*
- * This is used to generate a HTTP DIGEST response message ready for sending
+ * This is used to generate an HTTP DIGEST response message ready for sending
* to the recipient.
*
* Parameters:
diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
index 895b4a1..015bc66 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
@@ -471,4 +471,4 @@ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
krb5->token_max = 0;
}
-#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/
+#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5 */
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index c10fa6c..0141e17 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm.c
@@ -88,8 +88,6 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags)
fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
- if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
if(flags & (1<<10))
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.h b/Utilities/cmcurl/lib/vauth/ntlm.h
index 4dfda55..14ebba2 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.h
+++ b/Utilities/cmcurl/lib/vauth/ntlm.h
@@ -64,9 +64,6 @@
/* Indicates that the LAN Manager session key should be used for signing and
sealing authenticated communications. */
-#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
-/* unknown purpose */
-
#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
/* Indicates that NTLM authentication is being used. */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h
index af27f01..c310c66 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.h
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
@@ -104,11 +104,11 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
const char *service,
struct bufref *out);
-/* This is used to decode a HTTP DIGEST challenge message */
+/* This is used to decode an HTTP DIGEST challenge message */
CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
struct digestdata *digest);
-/* This is used to generate a HTTP DIGEST response message */
+/* This is used to generate an HTTP DIGEST response message */
CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index cb44eb4..c80841c 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.c
@@ -382,93 +382,145 @@ static const char * const protocols[] = {
NULL
};
-static curl_version_info_data version_info = {
- CURLVERSION_NOW,
- LIBCURL_VERSION,
- LIBCURL_VERSION_NUM,
- OS, /* as found by configure or set by hand at build-time */
- 0 /* features is 0 by default */
-#ifdef ENABLE_IPV6
- | CURL_VERSION_IPV6
+/*
+ * Feature presence run-time check functions.
+ *
+ * Warning: the value returned by these should not change between
+ * curl_global_init() and curl_global_cleanup() calls.
+ */
+
+#if defined(USE_LIBIDN2)
+static int idn_present(curl_version_info_data *info)
+{
+ return info->libidn != NULL;
+}
+#else
+#define idn_present NULL
#endif
-#ifdef USE_SSL
- | CURL_VERSION_SSL
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY)
+static int https_proxy_present(curl_version_info_data *info)
+{
+ (void) info;
+ return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY);
+}
#endif
-#ifdef USE_NTLM
- | CURL_VERSION_NTLM
+
+/*
+ * Features table.
+ *
+ * Keep the features alphabetically sorted.
+ * Use FEATURE() macro to define an entry: this allows documentation check.
+ */
+
+#define FEATURE(name, present, bitmask) {(name), (present), (bitmask)}
+
+struct feat {
+ const char *name;
+ int (*present)(curl_version_info_data *info);
+ int bitmask;
+};
+
+static const struct feat features_table[] = {
+#ifndef CURL_DISABLE_ALTSVC
+ FEATURE("alt-svc", NULL, CURL_VERSION_ALTSVC),
#endif
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
- defined(NTLM_WB_ENABLED)
- | CURL_VERSION_NTLM_WB
+#ifdef CURLRES_ASYNCH
+ FEATURE("AsynchDNS", NULL, CURL_VERSION_ASYNCHDNS),
#endif
-#ifdef USE_SPNEGO
- | CURL_VERSION_SPNEGO
+#ifdef HAVE_BROTLI
+ FEATURE("brotli", NULL, CURL_VERSION_BROTLI),
#endif
-#ifdef USE_KERBEROS5
- | CURL_VERSION_KERBEROS5
+#ifdef DEBUGBUILD
+ FEATURE("Debug", NULL, CURL_VERSION_DEBUG),
+#endif
+#ifdef USE_GSASL
+ FEATURE("gsasl", NULL, CURL_VERSION_GSASL),
#endif
#ifdef HAVE_GSSAPI
- | CURL_VERSION_GSSAPI
+ FEATURE("GSS-API", NULL, CURL_VERSION_GSSAPI),
#endif
-#ifdef USE_WINDOWS_SSPI
- | CURL_VERSION_SSPI
+#ifndef CURL_DISABLE_HSTS
+ FEATURE("HSTS", NULL, CURL_VERSION_HSTS),
#endif
-#ifdef HAVE_LIBZ
- | CURL_VERSION_LIBZ
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+ FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2),
#endif
-#ifdef DEBUGBUILD
- | CURL_VERSION_DEBUG
+#if defined(ENABLE_QUIC)
+ FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3),
#endif
-#ifdef CURLDEBUG
- | CURL_VERSION_CURLDEBUG
+#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY)
+ FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
-#ifdef CURLRES_ASYNCH
- | CURL_VERSION_ASYNCHDNS
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
+ FEATURE("IDN", idn_present, CURL_VERSION_IDN),
+#endif
+#ifdef ENABLE_IPV6
+ FEATURE("IPv6", NULL, CURL_VERSION_IPV6),
+#endif
+#ifdef USE_KERBEROS5
+ FEATURE("Kerberos", NULL, CURL_VERSION_KERBEROS5),
#endif
#if (SIZEOF_CURL_OFF_T > 4) && \
( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
- | CURL_VERSION_LARGEFILE
+ FEATURE("Largefile", NULL, CURL_VERSION_LARGEFILE),
#endif
-#if defined(WIN32) && defined(UNICODE) && defined(_UNICODE)
- | CURL_VERSION_UNICODE
-#endif
-#if defined(USE_TLS_SRP)
- | CURL_VERSION_TLSAUTH_SRP
+#ifdef HAVE_LIBZ
+ FEATURE("libz", NULL, CURL_VERSION_LIBZ),
#endif
-#if defined(USE_NGHTTP2) || defined(USE_HYPER)
- | CURL_VERSION_HTTP2
+#ifdef CURL_WITH_MULTI_SSL
+ FEATURE("MultiSSL", NULL, CURL_VERSION_MULTI_SSL),
#endif
-#if defined(ENABLE_QUIC)
- | CURL_VERSION_HTTP3
+#ifdef USE_NTLM
+ FEATURE("NTLM", NULL, CURL_VERSION_NTLM),
#endif
-#if defined(USE_UNIX_SOCKETS)
- | CURL_VERSION_UNIX_SOCKETS
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ FEATURE("NTLM_WB", NULL, CURL_VERSION_NTLM_WB),
#endif
#if defined(USE_LIBPSL)
- | CURL_VERSION_PSL
+ FEATURE("PSL", NULL, CURL_VERSION_PSL),
+#endif
+#ifdef USE_SPNEGO
+ FEATURE("SPNEGO", NULL, CURL_VERSION_SPNEGO),
#endif
-#if defined(CURL_WITH_MULTI_SSL)
- | CURL_VERSION_MULTI_SSL
+#ifdef USE_SSL
+ FEATURE("SSL", NULL, CURL_VERSION_SSL),
#endif
-#if defined(HAVE_BROTLI)
- | CURL_VERSION_BROTLI
+#ifdef USE_WINDOWS_SSPI
+ FEATURE("SSPI", NULL, CURL_VERSION_SSPI),
#endif
-#if defined(HAVE_ZSTD)
- | CURL_VERSION_ZSTD
+#ifdef GLOBAL_INIT_IS_THREADSAFE
+ FEATURE("threadsafe", NULL, CURL_VERSION_THREADSAFE),
#endif
-#ifndef CURL_DISABLE_ALTSVC
- | CURL_VERSION_ALTSVC
+#ifdef USE_TLS_SRP
+ FEATURE("TLS-SRP", NULL, CURL_VERSION_TLSAUTH_SRP),
#endif
-#ifndef CURL_DISABLE_HSTS
- | CURL_VERSION_HSTS
+#ifdef CURLDEBUG
+ FEATURE("TrackMemory", NULL, CURL_VERSION_CURLDEBUG),
+#endif
+#if defined(WIN32) && defined(UNICODE) && defined(_UNICODE)
+ FEATURE("Unicode", NULL, CURL_VERSION_UNICODE),
#endif
-#if defined(USE_GSASL)
- | CURL_VERSION_GSASL
+#ifdef USE_UNIX_SOCKETS
+ FEATURE("UnixSockets", NULL, CURL_VERSION_UNIX_SOCKETS),
#endif
-#if defined(GLOBAL_INIT_IS_THREADSAFE)
- | CURL_VERSION_THREADSAFE
+#ifdef HAVE_ZSTD
+ FEATURE("zstd", NULL, CURL_VERSION_ZSTD),
#endif
- ,
+ {NULL, NULL, 0}
+};
+
+static const char *feature_names[sizeof(features_table) /
+ sizeof(features_table[0])] = {NULL};
+
+
+static curl_version_info_data version_info = {
+ CURLVERSION_NOW,
+ LIBCURL_VERSION,
+ LIBCURL_VERSION_NUM,
+ OS, /* as found by configure or set by hand at build-time */
+ 0, /* features bitmask is built at run-time */
NULL, /* ssl_version */
0, /* ssl_version_num, this is kept at zero */
NULL, /* zlib_version */
@@ -496,11 +548,16 @@ static curl_version_info_data version_info = {
0, /* zstd_ver_num */
NULL, /* zstd version */
NULL, /* Hyper version */
- NULL /* gsasl version */
+ NULL, /* gsasl version */
+ feature_names
};
curl_version_info_data *curl_version_info(CURLversion stamp)
{
+ size_t n;
+ const struct feat *p;
+ int features = 0;
+
#if defined(USE_SSH)
static char ssh_buffer[80];
#endif
@@ -518,15 +575,11 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
static char zstd_buffer[80];
#endif
+ (void)stamp; /* avoid compiler warnings, we don't use this */
+
#ifdef USE_SSL
Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
version_info.ssl_version = ssl_buffer;
-#ifndef CURL_DISABLE_PROXY
- if(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY)
- version_info.features |= CURL_VERSION_HTTPS_PROXY;
- else
- version_info.features &= ~CURL_VERSION_HTTPS_PROXY;
-#endif
#endif
#ifdef HAVE_LIBZ
@@ -544,10 +597,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
/* This returns a version string if we use the given version or later,
otherwise it returns NULL */
version_info.libidn = idn2_check_version(IDN2_VERSION);
- if(version_info.libidn)
- version_info.features |= CURL_VERSION_IDN;
-#elif defined(USE_WIN32_IDN)
- version_info.features |= CURL_VERSION_IDN;
#endif
#if defined(USE_SSH)
@@ -597,6 +646,16 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
}
#endif
- (void)stamp; /* avoid compiler warnings, we don't use this */
+ /* Get available features, build bitmask and names array. */
+ n = 0;
+ for(p = features_table; p->name; p++)
+ if(!p->present || p->present(&version_info)) {
+ features |= p->bitmask;
+ feature_names[n++] = p->name;
+ }
+
+ feature_names[n] = NULL; /* Terminate array. */
+ version_info.features = features;
+
return &version_info;
}
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c
index 097cca4..f16b469 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/ngtcp2.c
@@ -27,6 +27,7 @@
#ifdef USE_NGTCP2
#include <ngtcp2/ngtcp2.h>
#include <nghttp3/nghttp3.h>
+
#ifdef USE_OPENSSL
#include <openssl/err.h>
#ifdef OPENSSL_IS_BORINGSSL
@@ -42,6 +43,7 @@
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
#include "vtls/wolfssl.h"
#endif
+
#include "urldata.h"
#include "sendf.h"
#include "strdup.h"
@@ -49,6 +51,7 @@
#include "ngtcp2.h"
#include "multiif.h"
#include "strcase.h"
+#include "cfilters.h"
#include "connect.h"
#include "strerror.h"
#include "dynbuf.h"
@@ -300,17 +303,19 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
static CURLcode quic_set_client_cert(struct Curl_easy *data,
struct quicsocket *qs)
{
- struct connectdata *conn = data->conn;
SSL_CTX *ssl_ctx = qs->sslctx;
- char *const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- const char *const ssl_cert_type = SSL_SET_OPTION(cert_type);
+ const struct ssl_config_data *ssl_config;
- if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
+ ssl_config = Curl_ssl_get_config(data, FIRSTSOCKET);
+ DEBUGASSERT(ssl_config);
+
+ if(ssl_config->primary.clientcert || ssl_config->primary.cert_blob
+ || ssl_config->cert_type) {
return Curl_ossl_set_client_cert(
- data, ssl_ctx, ssl_cert, ssl_cert_blob, ssl_cert_type,
- SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
- SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
+ data, ssl_ctx, ssl_config->primary.clientcert,
+ ssl_config->primary.cert_blob, ssl_config->cert_type,
+ ssl_config->key, ssl_config->key_blob,
+ ssl_config->key_type, ssl_config->key_passwd);
}
return CURLE_OK;
@@ -318,13 +323,17 @@ static CURLcode quic_set_client_cert(struct Curl_easy *data,
/** SSL callbacks ***/
-static int quic_init_ssl(struct quicsocket *qs)
+static CURLcode quic_init_ssl(struct quicsocket *qs,
+ struct Curl_easy *data,
+ struct connectdata *conn)
{
const uint8_t *alpn = NULL;
size_t alpnlen = 0;
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
+ (void)data;
+ (void)conn;
DEBUGASSERT(!qs->ssl);
qs->ssl = SSL_new(qs->sslctx);
@@ -339,64 +348,49 @@ static int quic_init_ssl(struct quicsocket *qs)
/* set SNI */
SSL_set_tlsext_host_name(qs->ssl, hostname);
- return 0;
+ return CURLE_OK;
}
#elif defined(USE_GNUTLS)
-static int quic_init_ssl(struct quicsocket *qs)
+static CURLcode quic_init_ssl(struct quicsocket *qs,
+ struct Curl_easy *data,
+ struct connectdata *conn)
{
+ CURLcode result;
gnutls_datum_t alpn[2];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
+ long * const pverifyresult = &data->set.ssl.certverifyresult;
int rc;
- DEBUGASSERT(!qs->ssl);
+ DEBUGASSERT(qs->gtls == NULL);
+ qs->gtls = calloc(1, sizeof(*(qs->gtls)));
+ if(!qs->gtls)
+ return CURLE_OUT_OF_MEMORY;
- gnutls_init(&qs->ssl, GNUTLS_CLIENT);
- gnutls_session_set_ptr(qs->ssl, &qs->conn_ref);
+ result = gtls_client_init(data, &conn->ssl_config, &data->set.ssl,
+ hostname, qs->gtls, pverifyresult);
+ if(result)
+ return result;
- if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) {
+ gnutls_session_set_ptr(qs->gtls->session, &qs->conn_ref);
+
+ if(ngtcp2_crypto_gnutls_configure_client_session(qs->gtls->session) != 0) {
H3BUGF(fprintf(stderr,
"ngtcp2_crypto_gnutls_configure_client_session failed\n"));
- return 1;
+ return CURLE_QUIC_CONNECT_ERROR;
}
- rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
+ rc = gnutls_priority_set_direct(qs->gtls->session, QUIC_PRIORITY, NULL);
if(rc < 0) {
H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
gnutls_strerror(rc)));
- return 1;
+ return CURLE_QUIC_CONNECT_ERROR;
}
/* Open the file if a TLS or QUIC backend has not done this before. */
Curl_tls_keylog_open();
if(Curl_tls_keylog_enabled()) {
- gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
- }
-
- if(qs->cred)
- gnutls_certificate_free_credentials(qs->cred);
-
- rc = gnutls_certificate_allocate_credentials(&qs->cred);
- if(rc < 0) {
- H3BUGF(fprintf(stderr,
- "gnutls_certificate_allocate_credentials failed: %s\n",
- gnutls_strerror(rc)));
- return 1;
- }
-
- rc = gnutls_certificate_set_x509_system_trust(qs->cred);
- if(rc < 0) {
- H3BUGF(fprintf(stderr,
- "gnutls_certificate_set_x509_system_trust failed: %s\n",
- gnutls_strerror(rc)));
- return 1;
- }
-
- rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
- if(rc < 0) {
- H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
- gnutls_strerror(rc)));
- return 1;
+ gnutls_session_set_keylog_function(qs->gtls->session, keylog_callback);
}
/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
@@ -405,11 +399,9 @@ static int quic_init_ssl(struct quicsocket *qs)
alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
alpn[1].size = sizeof(H3_ALPN_H3) - 2;
- gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
+ gnutls_alpn_set_protocols(qs->gtls->session, alpn, 2, GNUTLS_ALPN_MANDATORY);
- /* set SNI */
- gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
- return 0;
+ return CURLE_OK;
}
#elif defined(USE_WOLFSSL)
@@ -484,13 +476,17 @@ static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
/** SSL callbacks ***/
-static int quic_init_ssl(struct quicsocket *qs)
+static CURLcode quic_init_ssl(struct quicsocket *qs,
+ struct Curl_easy *data,
+ struct connectdata *conn)
{
const uint8_t *alpn = NULL;
size_t alpnlen = 0;
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
+ (void)data;
+ (void)conn;
DEBUGASSERT(!qs->ssl);
qs->ssl = SSL_new(qs->sslctx);
@@ -507,7 +503,7 @@ static int quic_init_ssl(struct quicsocket *qs)
wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME,
hostname, (unsigned short)strlen(hostname));
- return 0;
+ return CURLE_OK;
}
#endif /* defined(USE_WOLFSSL) */
@@ -812,8 +808,9 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
return CURLE_QUIC_CONNECT_ERROR;
#endif
- if(quic_init_ssl(qs))
- return CURLE_QUIC_CONNECT_ERROR;
+ result = quic_init_ssl(qs, data, conn);
+ if(result)
+ return result;
qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
@@ -845,7 +842,11 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
+#ifdef USE_GNUTLS
+ ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->gtls->session);
+#else
ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
+#endif
ngtcp2_connection_close_error_default(&qs->last_error);
@@ -894,7 +895,7 @@ static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
socks[0] = conn->sock[FIRSTSOCKET];
- /* in a HTTP/2 connection we can basically always get a frame so we should
+ /* in an HTTP/2 connection we can basically always get a frame so we should
always be ready for one */
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
@@ -932,29 +933,29 @@ static void qs_disconnect(struct quicsocket *qs)
close(qs->qlogfd);
qs->qlogfd = -1;
}
- if(qs->ssl)
#ifdef USE_OPENSSL
+ if(qs->ssl)
SSL_free(qs->ssl);
+ qs->ssl = NULL;
+ SSL_CTX_free(qs->sslctx);
#elif defined(USE_GNUTLS)
- gnutls_deinit(qs->ssl);
+ if(qs->gtls) {
+ if(qs->gtls->cred)
+ gnutls_certificate_free_credentials(qs->gtls->cred);
+ if(qs->gtls->session)
+ gnutls_deinit(qs->gtls->session);
+ free(qs->gtls);
+ qs->gtls = NULL;
+ }
#elif defined(USE_WOLFSSL)
+ if(qs->ssl)
wolfSSL_free(qs->ssl);
-#endif
qs->ssl = NULL;
-#ifdef USE_GNUTLS
- if(qs->cred) {
- gnutls_certificate_free_credentials(qs->cred);
- qs->cred = NULL;
- }
+ wolfSSL_CTX_free(qs->sslctx);
#endif
free(qs->pktbuf);
nghttp3_conn_del(qs->h3conn);
ngtcp2_conn_del(qs->qconn);
-#ifdef USE_OPENSSL
- SSL_CTX_free(qs->sslctx);
-#elif defined(USE_WOLFSSL)
- wolfSSL_CTX_free(qs->sslctx);
-#endif
}
void Curl_quic_disconnect(struct Curl_easy *data,
@@ -1170,7 +1171,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
}
}
else {
- /* store as a HTTP1-style header */
+ /* store as an HTTP1-style header */
result = write_data(stream, h3name.base, h3name.len);
if(result) {
return -1;
@@ -1672,6 +1673,15 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
struct connectdata *conn, int tempindex)
{
CURLcode result = CURLE_OK;
+ const char *hostname, *disp_hostname;
+ int port;
+ char *snihost;
+
+ Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+ snihost = Curl_ssl_snihost(data, hostname, NULL);
+ if(!snihost)
+ return CURLE_PEER_FAILED_VERIFICATION;
+
conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
conn->send[FIRSTSOCKET] = ngh3_stream_send;
conn->handler = &Curl_handler_http3;
@@ -1691,16 +1701,18 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
X509_free(server_cert);
if(result)
return result;
- infof(data, "Verified certificate just fine");
#elif defined(USE_GNUTLS)
- result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET);
+ result = Curl_gtls_verifyserver(data, conn->quic->gtls->session,
+ &conn->ssl_config, &data->set.ssl,
+ hostname, disp_hostname,
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
+ if(result)
+ return result;
#elif defined(USE_WOLFSSL)
- char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
- if(!snihost ||
- (wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE))
+ if(wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE)
return CURLE_PEER_FAILED_VERIFICATION;
- infof(data, "Verified certificate just fine");
#endif
+ infof(data, "Verified certificate just fine");
}
else
infof(data, "Skipped certificate verification");
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.h b/Utilities/cmcurl/lib/vquic/ngtcp2.h
index 6539f5f..2265999 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.h
+++ b/Utilities/cmcurl/lib/vquic/ngtcp2.h
@@ -36,14 +36,14 @@
#include <nghttp3/nghttp3.h>
#ifdef USE_OPENSSL
#include <openssl/ssl.h>
-#elif defined(USE_GNUTLS)
-#include <gnutls/gnutls.h>
#elif defined(USE_WOLFSSL)
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/quic.h>
#endif
+struct gtls_instance;
+
struct blocked_pkt {
const uint8_t *pkt;
size_t pktlen;
@@ -64,8 +64,7 @@ struct quicsocket {
SSL_CTX *sslctx;
SSL *ssl;
#elif defined(USE_GNUTLS)
- gnutls_certificate_credentials_t cred;
- gnutls_session_t ssl;
+ struct gtls_instance *gtls;
#elif defined(USE_WOLFSSL)
WOLFSSL_CTX *sslctx;
WOLFSSL *ssl;
diff --git a/Utilities/cmcurl/lib/vquic/quiche.c b/Utilities/cmcurl/lib/vquic/quiche.c
index a52a7e8..2b9a041 100644
--- a/Utilities/cmcurl/lib/vquic/quiche.c
+++ b/Utilities/cmcurl/lib/vquic/quiche.c
@@ -80,7 +80,7 @@ static int quiche_getsock(struct Curl_easy *data,
socks[0] = conn->sock[FIRSTSOCKET];
- /* in a HTTP/2 connection we can basically always get a frame so we should
+ /* in an HTTP/2 connection we can basically always get a frame so we should
always be ready for one */
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
@@ -348,9 +348,6 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
Curl_persistconninfo(data, conn, NULL, -1);
- /* for connection reuse purposes: */
- conn->ssl[FIRSTSOCKET].state = ssl_connection_complete;
-
{
unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL;
unsigned alpn_len, offset = 0;
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index 0105e40..d9fa58a 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/vssh/libssh.c
@@ -51,11 +51,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -71,6 +66,7 @@
#include "strdup.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "inet_ntop.h"
#include "parsedate.h" /* for the week day and month names */
@@ -1415,7 +1411,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
state(data, SSH_STOP);
break;
}
@@ -1662,13 +1658,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
CURLofft to_t;
CURLofft from_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+ from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
if(from_t == CURL_OFFT_FLOW) {
return CURLE_RANGE_ERROR;
}
while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+ to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
if(to_t == CURL_OFFT_FLOW) {
return CURLE_RANGE_ERROR;
}
@@ -2323,7 +2319,6 @@ CURLcode scp_perform(struct Curl_easy *data,
bool *connected, bool *dophase_done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
DEBUGF(infof(data, "DO phase starts"));
@@ -2334,7 +2329,7 @@ CURLcode scp_perform(struct Curl_easy *data,
result = myssh_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete"));
@@ -2504,7 +2499,6 @@ CURLcode sftp_perform(struct Curl_easy *data,
bool *dophase_done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
DEBUGF(infof(data, "DO phase starts"));
@@ -2516,7 +2510,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
/* run the state-machine */
result = myssh_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete"));
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index 5a2c0f8..ce9229f 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -54,11 +54,6 @@
#include <inet.h>
#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -74,6 +69,7 @@
#include "strdup.h"
#include "strcase.h"
#include "vtls/vtls.h"
+#include "cfilters.h"
#include "connect.h"
#include "inet_ntop.h"
#include "parsedate.h" /* for the week day and month names */
@@ -83,7 +79,6 @@
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
-#include "strcase.h"
#include <curl_base64.h> /* for base64 encoding/decoding */
#include <curl_sha256.h>
@@ -610,9 +605,9 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
/* remove old host+key that doesn't match */
if(host)
libssh2_knownhost_del(sshc->kh, host);
- /*FALLTHROUGH*/
+ /* FALLTHROUGH */
case CURLKHSTAT_FINE:
- /*FALLTHROUGH*/
+ /* FALLTHROUGH */
case CURLKHSTAT_FINE_ADD_TO_FILE:
/* proceed */
if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
@@ -785,7 +780,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
size_t keylen = 0;
int sshkeytype = 0;
int rc = 0;
- /* we handle the process to the callback*/
+ /* we handle the process to the callback */
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
&keylen, &sshkeytype);
if(remotekey) {
@@ -796,10 +791,14 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
Curl_set_in_callback(data, false);
if(rc!= CURLKHMATCH_OK) {
state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
}
}
else {
state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
}
return CURLE_OK;
}
@@ -2251,7 +2250,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
state(data, SSH_STOP);
break;
}
@@ -2503,12 +2502,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
CURLofft to_t;
CURLofft from_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+ from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
if(from_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+ to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
if(to_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
@@ -3375,7 +3374,6 @@ CURLcode scp_perform(struct Curl_easy *data,
bool *dophase_done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
DEBUGF(infof(data, "DO phase starts"));
@@ -3387,7 +3385,7 @@ CURLcode scp_perform(struct Curl_easy *data,
/* run the state-machine */
result = ssh_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete"));
@@ -3576,7 +3574,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
/* run the state-machine */
result = ssh_multi_statemach(data, dophase_done);
- *connected = data->conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete"));
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index c2f85f3..6a8fb56 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -31,6 +31,7 @@
#include <wolfssh/ssh.h>
#include <wolfssh/wolfsftp.h>
#include "urldata.h"
+#include "cfilters.h"
#include "connect.h"
#include "sendf.h"
#include "progress.h"
@@ -836,7 +837,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_READDIR_INIT:
Curl_pgrsSetDownloadSize(data, -1);
- if(data->set.opt_no_body) {
+ if(data->req.no_body) {
state(data, SSH_STOP);
break;
}
@@ -939,7 +940,6 @@ CURLcode wsftp_perform(struct Curl_easy *data,
bool *dophase_done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
DEBUGF(infof(data, "DO phase starts"));
@@ -951,7 +951,7 @@ CURLcode wsftp_perform(struct Curl_easy *data,
/* run the state-machine */
result = wssh_multi_statemach(data, dophase_done);
- *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+ *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete"));
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index 1221ce8..d9c0ce0 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -32,13 +32,17 @@
#include "sendf.h"
#include "inet_pton.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "connect.h"
#include "select.h"
#include "multiif.h"
#include "curl_printf.h"
-#include "curl_memory.h"
#include "strcase.h"
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
struct x509_context {
const br_x509_class *vtable;
br_x509_minimal_context minimal;
@@ -566,18 +570,20 @@ static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const char *hostname = SSL_HOST_NAME();
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char *hostname = connssl->hostname;
+ const bool verifypeer = conn_config->verifypeer;
+ const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
unsigned version_min, version_max;
#ifdef ENABLE_IPV6
@@ -588,7 +594,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
DEBUGASSERT(backend);
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_SSLv2:
failf(data, "BearSSL does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
@@ -659,11 +665,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
sizeof(backend->buf), 1);
- if(SSL_CONN_CONFIG(cipher_list)) {
+ if(conn_config->cipher_list) {
/* Override the ciphers as specified. For the default cipher list see the
BearSSL source code of br_ssl_client_init_full() */
ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
- SSL_CONN_CONFIG(cipher_list));
+ conn_config->cipher_list);
if(ret)
return ret;
}
@@ -674,19 +680,18 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
backend->x509.verifyhost = verifyhost;
br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *session;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
- &session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
infof(data, "BearSSL: re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
/* NOTE: when adding more protocols here, increase the size of the
@@ -696,7 +701,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
backend->protocols[cur++] = ALPN_H2;
@@ -753,17 +758,17 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_run_until(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
unsigned target)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- curl_socket_t sockfd = conn->sock[sockindex];
unsigned state;
unsigned char *buf;
size_t len;
ssize_t ret;
+ CURLcode result;
int err;
DEBUGASSERT(backend);
@@ -802,48 +807,37 @@ static CURLcode bearssl_run_until(struct Curl_easy *data,
return CURLE_OK;
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
- ret = swrite(sockfd, buf, len);
- if(ret == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- if(connssl->state != ssl_connection_complete)
- connssl->connecting_state = ssl_connect_2_writing;
- return CURLE_AGAIN;
- }
- return CURLE_WRITE_ERROR;
+ ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
+ if(ret <= 0) {
+ return result;
}
br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
}
else if(state & BR_SSL_RECVREC) {
buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
- ret = sread(sockfd, buf, len);
+ ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
}
- if(ret == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- if(connssl->state != ssl_connection_complete)
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_AGAIN;
- }
- return CURLE_READ_ERROR;
+ if(ret <= 0) {
+ return result;
}
br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
}
}
}
-static CURLcode bearssl_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CURLcode ret;
DEBUGASSERT(backend);
- ret = bearssl_run_until(data, conn, sockindex,
- BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+ ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
if(ret == CURLE_AGAIN)
return CURLE_OK;
if(ret == CURLE_OK) {
@@ -856,17 +850,18 @@ static CURLcode bearssl_connect_step2(struct Curl_easy *data,
return ret;
}
-static CURLcode bearssl_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode ret;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char *protocol;
protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
@@ -875,21 +870,21 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
#ifdef USE_HTTP2
if(!strcmp(protocol, ALPN_H2))
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
else
#endif
if(!strcmp(protocol, ALPN_HTTP_1_1))
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
else
infof(data, "ALPN, unrecognized protocol %s", protocol);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else
infof(data, VTLS_INFOF_NO_ALPN);
}
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *oldsession;
@@ -900,14 +895,10 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &oldsession, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
- ret = Curl_ssl_addsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- session, 0, sockindex, &added);
+ ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(session);
@@ -921,11 +912,10 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
return CURLE_OK;
}
-static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
+static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
@@ -933,7 +923,7 @@ static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
for(;;) {
- *err = bearssl_run_until(data, conn, sockindex, BR_SSL_SENDAPP);
+ *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP);
if (*err != CURLE_OK)
return -1;
app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
@@ -956,18 +946,17 @@ static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
}
}
-static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
+static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
DEBUGASSERT(backend);
- *err = bearssl_run_until(data, conn, sockindex, BR_SSL_RECVAPP);
+ *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP);
if(*err != CURLE_OK)
return -1;
app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
@@ -981,15 +970,14 @@ static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
return applen;
}
-static CURLcode bearssl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode ret;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1000,7 +988,7 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- ret = bearssl_connect_step1(data, conn, sockindex);
+ ret = bearssl_connect_step1(cf, data);
if(ret)
return ret;
}
@@ -1053,7 +1041,7 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- ret = bearssl_connect_step2(data, conn, sockindex);
+ ret = bearssl_connect_step2(cf, data);
if(ret || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1062,15 +1050,13 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
}
if(ssl_connect_3 == connssl->connecting_state) {
- ret = bearssl_connect_step3(data, conn, sockindex);
+ ret = bearssl_connect_step3(cf, data);
if(ret)
return ret;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = bearssl_recv;
- conn->send[sockindex] = bearssl_send;
*done = TRUE;
}
else
@@ -1087,13 +1073,14 @@ static size_t bearssl_version(char *buffer, size_t size)
return msnprintf(buffer, size, "BearSSL");
}
-static bool bearssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool bearssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return br_ssl_engine_current_state(&ctx->backend->ctx.eng) & BR_SSL_RECVAPP;
}
static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
@@ -1116,13 +1103,13 @@ static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-static CURLcode bearssl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode ret;
bool done = FALSE;
- ret = bearssl_connect_common(data, conn, sockindex, FALSE, &done);
+ ret = bearssl_connect_common(cf, data, FALSE, &done);
if(ret)
return ret;
@@ -1131,11 +1118,11 @@ static CURLcode bearssl_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return bearssl_connect_common(data, conn, sockindex, TRUE, done);
+ return bearssl_connect_common(cf, data, TRUE, done);
}
static void *bearssl_get_internals(struct ssl_connect_data *connssl,
@@ -1146,22 +1133,24 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl,
return &backend->ctx;
}
-static void bearssl_close(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
size_t i;
DEBUGASSERT(backend);
if(backend->active) {
+ backend->active = FALSE;
br_ssl_engine_close(&backend->ctx.eng);
- (void)bearssl_run_until(data, conn, sockindex, BR_SSL_CLOSED);
+ (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
+ }
+ if(backend->anchors) {
+ for(i = 0; i < backend->anchors_len; ++i)
+ free(backend->anchors[i].dn.data);
+ Curl_safefree(backend->anchors);
}
- for(i = 0; i < backend->anchors_len; ++i)
- free(backend->anchors[i].dn.data);
- free(backend->anchors);
}
static void bearssl_session_free(void *ptr)
@@ -1184,7 +1173,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
const struct Curl_ssl Curl_ssl_bearssl = {
{ CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
- SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX,
+ SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */
@@ -1197,7 +1186,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1208,7 +1197,10 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_false_start, /* false_start */
bearssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ bearssl_recv, /* recv decrypted data */
+ bearssl_send, /* send data to encrypt */
};
#endif /* USE_BEARSSL */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 4ee4ede..2074dca 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -73,6 +73,7 @@
#include "sendf.h"
#include "gskit.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "strcase.h"
@@ -105,10 +106,8 @@
struct ssl_backend_data {
gsk_handle handle;
int iocport;
-#ifndef CURL_DISABLE_PROXY
int localfd;
int remotefd;
-#endif
};
#define BACKEND connssl->backend
@@ -295,11 +294,12 @@ static CURLcode set_numeric(struct Curl_easy *data,
}
-static CURLcode set_ciphers(struct Curl_easy *data,
+static CURLcode set_ciphers(struct Curl_cfilter *cf, struct Curl_easy *data,
gsk_handle h, unsigned int *protoflags)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct connectdata *conn = data->conn;
- const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
+ const char *cipherlist = conn_config->cipher_list;
const char *clp;
const struct gskit_cipher *ctp;
int i;
@@ -324,7 +324,7 @@ static CURLcode set_ciphers(struct Curl_easy *data,
GSKit tokens are always shorter than their cipher names, allocated buffers
will always be large enough to accommodate the result. */
l = strlen(cipherlist) + 1;
- memset((char *) ciphers, 0, sizeof(ciphers));
+ memset(ciphers, 0, sizeof(ciphers));
for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
ciphers[i].buf = malloc(l);
if(!ciphers[i].buf) {
@@ -490,14 +490,16 @@ static CURLcode init_environment(struct Curl_easy *data,
}
-static void cancel_async_handshake(struct connectdata *conn, int sockindex)
+static void cancel_async_handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
Qso_OverlappedIO_t cstat;
+ (void)data;
DEBUGASSERT(BACKEND);
- if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
+ if(QsoCancelOperation(cf->conn->sock[cf->sockindex], 0) > 0)
QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL);
}
@@ -509,12 +511,12 @@ static void close_async_handshake(struct ssl_connect_data *connssl)
BACKEND->iocport = -1;
}
-static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
- int directions)
+static int pipe_ssloverssl(struct Curl_cfilter *cf, int directions)
{
-#ifndef CURL_DISABLE_PROXY
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
struct pollfd fds[2];
int n;
int m;
@@ -523,14 +525,14 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
char buf[CURL_MAX_WRITE_SIZE];
DEBUGASSERT(BACKEND);
- DEBUGASSERT(connproxyssl->backend);
- if(!connssl->use || !connproxyssl->use)
+ if(!connssl_next)
return 0; /* No SSL over SSL: OK. */
+ DEBUGASSERT(connssl_next->backend);
n = 1;
fds[0].fd = BACKEND->remotefd;
- fds[1].fd = conn->sock[sockindex];
+ fds[1].fd = cf->conn->sock[cf->sockindex];
if(directions & SOS_READ) {
fds[0].events |= POLLOUT;
@@ -547,7 +549,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
if(fds[0].revents & POLLOUT) {
/* Try getting data from HTTPS proxy and pipe it upstream. */
n = 0;
- i = gsk_secure_soc_read(connproxyssl->backend->handle,
+ i = gsk_secure_soc_read(connssl_next->backend->handle,
buf, sizeof(buf), &n);
switch(i) {
case GSK_OK:
@@ -572,7 +574,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
if(n < 0)
return -1;
if(n) {
- i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
+ i = gsk_secure_soc_write(connssl_next->backend->handle, buf, n, &m);
if(i != GSK_OK || n != m)
return -1;
ret = 1;
@@ -580,24 +582,21 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
}
return ret; /* OK */
-#else
- return 0;
-#endif
}
-static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void close_one(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+
DEBUGASSERT(BACKEND);
if(BACKEND->handle) {
gskit_status(data, gsk_secure_soc_close(&BACKEND->handle),
"gsk_secure_soc_close()", 0);
/* Last chance to drain output. */
- while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
+ while(pipe_ssloverssl(cf, SOS_WRITE) > 0)
;
BACKEND->handle = (gsk_handle) NULL;
-#ifndef CURL_DISABLE_PROXY
if(BACKEND->localfd >= 0) {
close(BACKEND->localfd);
BACKEND->localfd = -1;
@@ -606,30 +605,29 @@ static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
close(BACKEND->remotefd);
BACKEND->remotefd = -1;
}
-#endif
}
if(BACKEND->iocport >= 0)
close_async_handshake(connssl);
}
-static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
+static ssize_t gskit_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *mem, size_t len, CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode cc = CURLE_SEND_ERROR;
int written;
DEBUGASSERT(BACKEND);
- if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
+ if(pipe_ssloverssl(cf, SOS_WRITE) >= 0) {
cc = gskit_status(data,
gsk_secure_soc_write(BACKEND->handle,
(char *) mem, (int) len, &written),
"gsk_secure_soc_write()", CURLE_SEND_ERROR);
if(cc == CURLE_OK)
- if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_WRITE) < 0)
cc = CURLE_SEND_ERROR;
}
if(cc != CURLE_OK) {
@@ -640,17 +638,18 @@ static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
}
-static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
- size_t buffersize, CURLcode *curlcode)
+static ssize_t gskit_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t buffersize, CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
int nread;
CURLcode cc = CURLE_RECV_ERROR;
+ (void)data;
DEBUGASSERT(BACKEND);
- if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
+ if(pipe_ssloverssl(cf, SOS_READ) >= 0) {
int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
buf, buffsize, &nread),
@@ -670,11 +669,14 @@ static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
}
static CURLcode
-set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
+set_ssl_version_min_max(unsigned int *protoflags,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct connectdata *conn = data->conn;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
@@ -702,35 +704,36 @@ set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
return CURLE_OK;
}
-static CURLcode gskit_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
gsk_handle envir;
CURLcode result;
- const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
- const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
- const char * const keyringlabel = SSL_SET_OPTION(primary.clientcert);
- const long int ssl_version = SSL_CONN_CONFIG(version);
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const hostname = SSL_HOST_NAME();
+ const char * const keyringfile = conn_config->CAfile;
+ const char * const keyringpwd = conn_config->key_passwd;
+ const char * const keyringlabel = ssl_config->primary.clientcert;
+ const long int ssl_version = conn_config->version;
+ const bool verifypeer = conn_config->verifypeer;
+ const char *hostname = connssl->hostname;
const char *sni;
unsigned int protoflags = 0;
Qso_OverlappedIO_t commarea;
-#ifndef CURL_DISABLE_PROXY
int sockpair[2];
static const int sobufsize = CURL_MAX_WRITE_SIZE;
-#endif
/* Create SSL environment, start (preferably asynchronous) handshake. */
DEBUGASSERT(BACKEND);
BACKEND->handle = (gsk_handle) NULL;
BACKEND->iocport = -1;
-#ifndef CURL_DISABLE_PROXY
BACKEND->localfd = -1;
BACKEND->remotefd = -1;
-#endif
/* GSKit supports two ways of specifying an SSL context: either by
* application identifier (that should have been defined at the system
@@ -769,9 +772,8 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(result)
return result;
-#ifndef CURL_DISABLE_PROXY
/* Establish a pipelining socket pair for SSL over SSL. */
- if(conn->proxy_ssl[sockindex].use) {
+ if(connssl_next) {
if(Curl_socketpair(0, 0, 0, sockpair))
return CURLE_SSL_CONNECT_ERROR;
BACKEND->localfd = sockpair[0];
@@ -787,7 +789,6 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
curlx_nonblock(BACKEND->localfd, TRUE);
curlx_nonblock(BACKEND->remotefd, TRUE);
}
-#endif
/* Determine which SSL/TLS version should be enabled. */
sni = hostname;
@@ -809,7 +810,7 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
- result = set_ssl_version_min_max(&protoflags, data);
+ result = set_ssl_version_min_max(&protoflags, cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -845,15 +846,10 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(!result)
result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
if(!result)
-#ifndef CURL_DISABLE_PROXY
result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
- BACKEND->localfd: conn->sock[sockindex]);
-#else
- result = set_numeric(data, BACKEND->handle, GSK_FD,
- conn->sock[sockindex]);
-#endif
+ BACKEND->localfd: cf->conn->sock[cf->sockindex]);
if(!result)
- result = set_ciphers(data, BACKEND->handle, &protoflags);
+ result = set_ciphers(cf, data, BACKEND->handle, &protoflags);
if(!protoflags) {
failf(data, "No SSL protocol/cipher combination enabled");
result = CURLE_SSL_CIPHER;
@@ -920,12 +916,10 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
else if(errno != ENOBUFS)
result = gskit_status(data, GSK_ERROR_IO,
"QsoCreateIOCompletionPort()", 0);
-#ifndef CURL_DISABLE_PROXY
- else if(conn->proxy_ssl[sockindex].use) {
+ else if(connssl_next) {
/* Cannot pipeline while handshaking synchronously. */
result = CURLE_SSL_CONNECT_ERROR;
}
-#endif
else {
/* No more completion port available. Use synchronous IO. */
result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
@@ -943,11 +937,11 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
}
-static CURLcode gskit_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
Qso_OverlappedIO_t cstat;
struct timeval stmv;
CURLcode result;
@@ -975,7 +969,7 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
char buffer[STRERROR_LEN];
failf(data, "QsoWaitForIOCompletion() I/O error: %s",
Curl_strerror(errno, buffer, sizeof(buffer)));
- cancel_async_handshake(conn, sockindex);
+ cancel_async_handshake(cf, data);
close_async_handshake(connssl);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -983,7 +977,7 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
case 0: /* Handshake in progress, timeout occurred. */
if(nonblocking)
return CURLE_OK;
- cancel_async_handshake(conn, sockindex);
+ cancel_async_handshake(cf, data);
close_async_handshake(connssl);
return CURLE_OPERATION_TIMEDOUT;
}
@@ -998,15 +992,15 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
}
-static CURLcode gskit_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
const gsk_cert_data_elem *cdev;
int cdec;
const gsk_cert_data_elem *p;
const char *cert = (const char *) NULL;
- const char *certend;
+ const char *certend = (const char *) NULL;
const char *ptr;
CURLcode result;
@@ -1044,7 +1038,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
/* Verify host. */
- result = Curl_verifyhost(data, conn, cert, certend);
+ result = Curl_verifyhost(cf, data, cert, certend);
if(result)
return result;
@@ -1066,7 +1060,9 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
/* Check pinned public key. */
- ptr = SSL_PINNED_PUB_KEY();
+ ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(!result && ptr) {
struct Curl_X509certificate x509;
struct Curl_asn1Element *p;
@@ -1087,11 +1083,11 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
-static CURLcode gskit_connect_common(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking, bool *done)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
timediff_t timeout_ms;
CURLcode result = CURLE_OK;
@@ -1110,12 +1106,12 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
result = CURLE_OPERATION_TIMEDOUT;
}
else
- result = gskit_connect_step1(data, conn, sockindex);
+ result = gskit_connect_step1(cf, data);
}
/* Handle handshake pipelining. */
if(!result)
- if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_READ | SOS_WRITE) < 0)
result = CURLE_SSL_CONNECT_ERROR;
/* Step 2: check if handshake is over. */
@@ -1129,25 +1125,23 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
result = CURLE_OPERATION_TIMEDOUT;
}
else
- result = gskit_connect_step2(data, conn, sockindex, nonblocking);
+ result = gskit_connect_step2(cf, data, nonblocking);
}
/* Handle handshake pipelining. */
if(!result)
- if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_READ | SOS_WRITE) < 0)
result = CURLE_SSL_CONNECT_ERROR;
/* Step 3: gather certificate info, verify host. */
if(!result && connssl->connecting_state == ssl_connect_3)
- result = gskit_connect_step3(data, conn, sockindex);
+ result = gskit_connect_step3(cf, data);
if(result)
close_one(connssl, data, conn, sockindex);
else if(connssl->connecting_state == ssl_connect_done) {
connssl->state = ssl_connection_complete;
connssl->connecting_state = ssl_connect_1;
- conn->recv[sockindex] = gskit_recv;
- conn->send[sockindex] = gskit_send;
*done = TRUE;
}
@@ -1155,27 +1149,29 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
}
-static CURLcode gskit_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode gskit_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
- result = gskit_connect_common(data, conn, sockindex, TRUE, done);
+ result = gskit_connect_common(cf, data, TRUE, done);
if(*done || result)
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ connssl->connecting_state = ssl_connect_1;
return result;
}
-static CURLcode gskit_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
bool done;
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
- result = gskit_connect_common(data, conn, sockindex, FALSE, &done);
+ connssl->connecting_state = ssl_connect_1;
+ result = gskit_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1185,20 +1181,16 @@ static CURLcode gskit_connect(struct Curl_easy *data,
}
-static void gskit_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void gskit_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- close_one(&conn->ssl[sockindex], data, conn, sockindex);
-#ifndef CURL_DISABLE_PROXY
- close_one(&conn->proxy_ssl[sockindex], data, conn, sockindex);
-#endif
+ close_one(cf, data);
}
-static int gskit_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int gskit_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
int what;
int rc;
char buf[120];
@@ -1214,9 +1206,9 @@ static int gskit_shutdown(struct Curl_easy *data,
return 0;
#endif
- close_one(connssl, data, conn, sockindex);
+ close_one(cf, data);
rc = 0;
- what = SOCKET_READABLE(conn->sock[sockindex],
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
while(loop--) {
@@ -1238,7 +1230,7 @@ static int gskit_shutdown(struct Curl_easy *data,
notify alert from the server. No way to gsk_secure_soc_read() now, so
use read(). */
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
+ nread = read(cf->conn->sock[cf->sockindex], buf, sizeof(buf));
if(nread < 0) {
char buffer[STRERROR_LEN];
@@ -1249,7 +1241,7 @@ static int gskit_shutdown(struct Curl_easy *data,
if(nread <= 0)
break;
- what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0);
}
return rc;
@@ -1262,12 +1254,14 @@ static size_t gskit_version(char *buffer, size_t size)
}
-static int gskit_check_cxn(struct connectdata *cxn)
+static int gskit_check_cxn(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
int err;
int errlen;
+ (void)data;
/* The only thing that can be tested here is at the socket level. */
DEBUGASSERT(BACKEND);
@@ -1311,7 +1305,7 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_cert_status_request, /* cert_status_request */
gskit_connect, /* connect */
gskit_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
gskit_get_internals, /* get_internals */
gskit_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1323,7 +1317,10 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ gskit_recv, /* recv decrypted data */
+ gskit_send, /* send data to encrypt */
};
#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index cf3dbc5..104dce6 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -45,6 +45,7 @@
#include "inet_pton.h"
#include "gtls.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "vauth/vauth.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
@@ -58,14 +59,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-#ifdef HAVE_GNUTLS_SRP
-/* the function exists */
-#ifdef USE_TLS_SRP
-/* the functionality is not disabled */
-#define USE_GNUTLS_SRP
-#endif
-#endif
-
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -84,35 +77,43 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
struct ssl_backend_data {
- gnutls_session_t session;
- gnutls_certificate_credentials_t cred;
-#ifdef USE_GNUTLS_SRP
- gnutls_srp_client_credentials_t srp_client_cred;
-#endif
+ struct gtls_instance gtls;
};
-static ssize_t gtls_push(void *s, const void *buf, size_t len)
+static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
- curl_socket_t sock = *(curl_socket_t *)s;
- ssize_t ret = swrite(sock, buf, len);
- return ret;
-}
+ struct Curl_cfilter *cf = s;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
-static ssize_t gtls_pull(void *s, void *buf, size_t len)
-{
- curl_socket_t sock = *(curl_socket_t *)s;
- ssize_t ret = sread(sock, buf, len);
- return ret;
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ if(nwritten < 0) {
+ gnutls_transport_set_errno(connssl->backend->gtls.session,
+ (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ nwritten = -1;
+ }
+ return nwritten;
}
-static ssize_t gtls_push_ssl(void *s, const void *buf, size_t len)
+static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
- return gnutls_record_send((gnutls_session_t) s, buf, len);
-}
+ struct Curl_cfilter *cf = s;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
-static ssize_t gtls_pull_ssl(void *s, void *buf, size_t len)
-{
- return gnutls_record_recv((gnutls_session_t) s, buf, len);
+ DEBUGASSERT(data);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ if(nread < 0) {
+ gnutls_transport_set_errno(connssl->backend->gtls.session,
+ (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ nread = -1;
+ }
+ return nread;
}
/* gtls_init()
@@ -205,19 +206,18 @@ static void unload_file(gnutls_datum_t data)
/* this function does a SSL/TLS (re-)handshake */
-static CURLcode handshake(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool duringconnect,
bool nonblocking)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
gnutls_session_t session;
- curl_socket_t sockfd = conn->sock[sockindex];
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
DEBUGASSERT(backend);
- session = backend->session;
+ session = backend->gtls.session;
for(;;) {
timediff_t timeout_ms;
@@ -323,12 +323,12 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
static CURLcode
set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_primary_config *conn_config,
const char **prioritylist,
const char *tls13support)
{
- struct connectdata *conn = data->conn;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
(ssl_version == CURL_SSLVERSION_TLSv1))
@@ -394,20 +394,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-static CURLcode
-gtls_connect_step1(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+CURLcode gtls_client_init(struct Curl_easy *data,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ const char *hostname,
+ struct gtls_instance *gtls,
+ long *pverifyresult)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
unsigned int init_flags;
- gnutls_session_t session;
int rc;
bool sni = TRUE; /* default is SNI enabled */
- void *transport_ptr = NULL;
- gnutls_push_func gnutls_transport_push = NULL;
- gnutls_pull_func gnutls_transport_pull = NULL;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -415,54 +411,44 @@ gtls_connect_step1(struct Curl_easy *data,
#endif
const char *prioritylist;
const char *err = NULL;
- const char * const hostname = SSL_HOST_NAME();
- long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
const char *tls13support;
CURLcode result;
- DEBUGASSERT(backend);
-
- if(connssl->state == ssl_connection_complete)
- /* to make us tolerant against being called more than once for the
- same connection */
- return CURLE_OK;
-
if(!gtls_inited)
gtls_init();
- /* Initialize certverifyresult to OK */
- *certverifyresult = 0;
+ *pverifyresult = 0;
- if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
+ if(config->version == CURL_SSLVERSION_SSLv2) {
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
- else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
+ else if(config->version == CURL_SSLVERSION_SSLv3)
sni = FALSE; /* SSLv3 has no SNI */
/* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(&backend->cred);
+ rc = gnutls_certificate_allocate_credentials(&gtls->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
}
#ifdef USE_GNUTLS_SRP
- if((SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) &&
+ if((config->authtype == CURL_TLSAUTH_SRP) &&
Curl_auth_allowed_to_host(data)) {
- infof(data, "Using TLS-SRP username: %s",
- SSL_SET_OPTION(primary.username));
+ infof(data, "Using TLS-SRP username: %s", config->username);
- rc = gnutls_srp_allocate_client_credentials(&backend->srp_client_cred);
+ rc = gnutls_srp_allocate_client_credentials(
+ &gtls->srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
gnutls_strerror(rc));
return CURLE_OUT_OF_MEMORY;
}
- rc = gnutls_srp_set_client_credentials(backend->srp_client_cred,
- SSL_SET_OPTION(primary.username),
- SSL_SET_OPTION(primary.password));
+ rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+ config->username,
+ config->password);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_srp_set_client_cred() failed: %s",
gnutls_strerror(rc));
@@ -471,67 +457,63 @@ gtls_connect_step1(struct Curl_easy *data,
}
#endif
- if(SSL_CONN_CONFIG(CAfile)) {
+ if(config->CAfile) {
/* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(backend->cred,
+ gnutls_certificate_set_verify_flags(gtls->cred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
- rc = gnutls_certificate_set_x509_trust_file(backend->cred,
- SSL_CONN_CONFIG(CAfile),
+ rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
+ config->CAfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)",
- SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
- if(SSL_CONN_CONFIG(verifypeer)) {
- *certverifyresult = rc;
+ config->CAfile, gnutls_strerror(rc));
+ if(config->verifypeer) {
+ *pverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
else
- infof(data, "found %d certificates in %s", rc,
- SSL_CONN_CONFIG(CAfile));
+ infof(data, "found %d certificates in %s", rc, config->CAfile);
}
- if(SSL_CONN_CONFIG(CApath)) {
+ if(config->CApath) {
/* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(backend->cred,
- SSL_CONN_CONFIG(CApath),
+ rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
+ config->CApath,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)",
- SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
- if(SSL_CONN_CONFIG(verifypeer)) {
- *certverifyresult = rc;
+ config->CApath, gnutls_strerror(rc));
+ if(config->verifypeer) {
+ *pverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
else
- infof(data, "found %d certificates in %s",
- rc, SSL_CONN_CONFIG(CApath));
+ infof(data, "found %d certificates in %s", rc, config->CApath);
}
#ifdef CURL_CA_FALLBACK
/* use system ca certificate store as fallback */
- if(SSL_CONN_CONFIG(verifypeer) &&
- !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
+ if(config->verifypeer && !(config->CAfile || config->CApath)) {
/* this ignores errors on purpose */
- gnutls_certificate_set_x509_system_trust(backend->cred);
+ gnutls_certificate_set_x509_system_trust(gtls->cred);
}
#endif
- if(SSL_SET_OPTION(primary.CRLfile)) {
+ if(config->CRLfile) {
/* set the CRL list file */
- rc = gnutls_certificate_set_x509_crl_file(backend->cred,
- SSL_SET_OPTION(primary.CRLfile),
+ rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
+ config->CRLfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
failf(data, "error reading crl file %s (%s)",
- SSL_SET_OPTION(primary.CRLfile), gnutls_strerror(rc));
+ config->CRLfile, gnutls_strerror(rc));
return CURLE_SSL_CRL_BADFILE;
}
else
- infof(data, "found %d CRL in %s",
- rc, SSL_SET_OPTION(primary.CRLfile));
+ infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
/* Initialize TLS session as a client */
@@ -546,15 +528,12 @@ gtls_connect_step1(struct Curl_easy *data,
init_flags |= GNUTLS_NO_TICKETS;
#endif
- rc = gnutls_init(&backend->session, init_flags);
+ rc = gnutls_init(&gtls->session, init_flags);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_init() failed: %d", rc);
return CURLE_SSL_CONNECT_ERROR;
}
- /* convenient assign */
- session = backend->session;
-
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
@@ -562,15 +541,15 @@ gtls_connect_step1(struct Curl_easy *data,
sni) {
size_t snilen;
char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
- if(!snihost || gnutls_server_name_set(session, GNUTLS_NAME_DNS, snihost,
- snilen) < 0) {
+ if(!snihost || gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
+ snihost, snilen) < 0) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
}
/* Use default priorities */
- rc = gnutls_set_default_priority(session);
+ rc = gnutls_set_default_priority(gtls->session);
if(rc != GNUTLS_E_SUCCESS)
return CURLE_SSL_CONNECT_ERROR;
@@ -581,13 +560,13 @@ gtls_connect_step1(struct Curl_easy *data,
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
- if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 ||
- SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) {
+ if(config->version == CURL_SSLVERSION_SSLv2 ||
+ config->version == CURL_SSLVERSION_SSLv3) {
failf(data, "GnuTLS does not support SSLv2 or SSLv3");
return CURLE_SSL_CONNECT_ERROR;
}
- if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_TLSv1_3) {
+ if(config->version == CURL_SSLVERSION_TLSv1_3) {
if(!tls13support) {
failf(data, "This GnuTLS installation does not support TLS 1.3");
return CURLE_SSL_CONNECT_ERROR;
@@ -595,14 +574,14 @@ gtls_connect_step1(struct Curl_easy *data,
}
/* At this point we know we have a supported TLS version, so set it */
- result = set_ssl_version_min_max(data, &prioritylist, tls13support);
+ result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
if(result)
return result;
#ifdef USE_GNUTLS_SRP
/* Only add SRP to the cipher list if SRP is requested. Otherwise
* GnuTLS will disable TLS 1.3 support. */
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) {
+ if(config->authtype == CURL_TLSAUTH_SRP) {
size_t len = strlen(prioritylist);
char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1);
@@ -610,7 +589,7 @@ gtls_connect_step1(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
strcpy(prioritysrp, prioritylist);
strcpy(prioritysrp + len, ":" GNUTLS_SRP);
- rc = gnutls_priority_set_direct(session, prioritysrp, &err);
+ rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
free(prioritysrp);
if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
@@ -620,7 +599,7 @@ gtls_connect_step1(struct Curl_easy *data,
else {
#endif
infof(data, "GnuTLS ciphers: %s", prioritylist);
- rc = gnutls_priority_set_direct(session, prioritylist, &err);
+ rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err);
#ifdef USE_GNUTLS_SRP
}
#endif
@@ -631,48 +610,19 @@ gtls_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- if(conn->bits.tls_enable_alpn) {
- int cur = 0;
- gnutls_datum_t protocols[2];
-
-#ifdef USE_HTTP2
- if(data->state.httpwant >= CURL_HTTP_VERSION_2
-#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
-#endif
- ) {
- protocols[cur].data = (unsigned char *)ALPN_H2;
- protocols[cur].size = ALPN_H2_LENGTH;
- cur++;
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
- }
-#endif
-
- protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
- protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
- cur++;
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
-
- if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) {
- failf(data, "failed setting ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- if(SSL_SET_OPTION(primary.clientcert)) {
- if(SSL_SET_OPTION(key_passwd)) {
+ if(config->clientcert) {
+ if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
GNUTLS_PKCS_USE_PBES2_AES_256;
rc = gnutls_certificate_set_x509_key_file2(
- backend->cred,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key) ?
- SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
- do_file_type(SSL_SET_OPTION(cert_type)),
- SSL_SET_OPTION(key_passwd),
+ gtls->cred,
+ config->clientcert,
+ ssl_config->key ? ssl_config->key : config->clientcert,
+ do_file_type(ssl_config->cert_type),
+ ssl_config->key_passwd,
supported_key_encryption_algorithms);
if(rc != GNUTLS_E_SUCCESS) {
failf(data,
@@ -683,11 +633,10 @@ gtls_connect_step1(struct Curl_easy *data,
}
else {
if(gnutls_certificate_set_x509_key_file(
- backend->cred,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key) ?
- SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
- do_file_type(SSL_SET_OPTION(cert_type)) ) !=
+ gtls->cred,
+ config->clientcert,
+ ssl_config->key ? ssl_config->key : config->clientcert,
+ do_file_type(ssl_config->cert_type) ) !=
GNUTLS_E_SUCCESS) {
failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR;
@@ -697,9 +646,9 @@ gtls_connect_step1(struct Curl_easy *data,
#ifdef USE_GNUTLS_SRP
/* put the credentials to the current session */
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) {
- rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
- backend->srp_client_cred);
+ if(config->authtype == CURL_TLSAUTH_SRP) {
+ rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP,
+ gtls->srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -708,59 +657,88 @@ gtls_connect_step1(struct Curl_easy *data,
else
#endif
{
- rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
- backend->cred);
+ rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
+ gtls->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
}
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *proxy_backend;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(proxy_backend);
- transport_ptr = proxy_backend->session;
- gnutls_transport_push = gtls_push_ssl;
- gnutls_transport_pull = gtls_pull_ssl;
- }
- else
-#endif
- {
- /* file descriptor for the socket */
- transport_ptr = &conn->sock[sockindex];
- gnutls_transport_push = gtls_push;
- gnutls_transport_pull = gtls_pull;
+ if(config->verifystatus) {
+ rc = gnutls_ocsp_status_request_enable_client(gtls->session,
+ NULL, 0, NULL);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
- /* set the connection handle */
- gnutls_transport_set_ptr(session, transport_ptr);
+ return CURLE_OK;
+}
+
+static CURLcode
+gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ long * const pverifyresult = &ssl_config->certverifyresult;
+ CURLcode result;
- /* register callback functions to send and receive data. */
- gnutls_transport_set_push_function(session, gnutls_transport_push);
- gnutls_transport_set_pull_function(session, gnutls_transport_pull);
+ DEBUGASSERT(backend);
- if(SSL_CONN_CONFIG(verifystatus)) {
- rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
+ if(connssl->state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ result = gtls_client_init(data, conn_config, ssl_config,
+ connssl->hostname,
+ &backend->gtls, pverifyresult);
+ if(result)
+ return result;
+
+ if(cf->conn->bits.tls_enable_alpn) {
+ int cur = 0;
+ gnutls_datum_t protocols[2];
+
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
+#endif
+ ) {
+ protocols[cur].data = (unsigned char *)ALPN_H2;
+ protocols[cur].size = ALPN_H2_LENGTH;
+ cur++;
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
+ }
+#endif
+
+ protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
+ protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
+ cur++;
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
+
+ if(gnutls_alpn_set_protocols(backend->gtls.session, protocols, cur, 0)) {
+ failf(data, "failed setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
}
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(conn_config->sessionid) {
void *ssl_sessionid;
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, &ssl_idsize, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
- gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+ gnutls_session_set_data(backend->gtls.session,
+ ssl_sessionid, ssl_idsize);
/* Informational message */
infof(data, "SSL re-using session ID");
@@ -768,6 +746,11 @@ gtls_connect_step1(struct Curl_easy *data,
Curl_ssl_sessionid_unlock(data);
}
+ /* register callback functions and handle to send and receive data. */
+ gnutls_transport_set_ptr(backend->gtls.session, cf);
+ gnutls_transport_set_push_function(backend->gtls.session, gtls_push);
+ gnutls_transport_set_pull_function(backend->gtls.session, gtls_pull);
+
return CURLE_OK;
}
@@ -829,14 +812,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
return result;
}
-static Curl_recv gtls_recv;
-static Curl_send gtls_send;
-
CURLcode
Curl_gtls_verifyserver(struct Curl_easy *data,
- struct connectdata *conn,
gnutls_session_t session,
- int sockindex)
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ const char *hostname,
+ const char *dispname,
+ const char *pinned_key)
{
unsigned int cert_list_size;
const gnutls_datum_t *chainp;
@@ -849,15 +832,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
time_t certclock;
const char *ptr;
int rc;
- gnutls_datum_t proto;
CURLcode result = CURLE_OK;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
unsigned int algo;
unsigned int bits;
gnutls_protocol_t version = gnutls_protocol_get_version(session);
#endif
- const char * const hostname = SSL_HOST_NAME();
- long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
+ long * const certverifyresult = &ssl_config->certverifyresult;
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -875,13 +856,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
if(!chainp) {
- if(SSL_CONN_CONFIG(verifypeer) ||
- SSL_CONN_CONFIG(verifyhost) ||
- SSL_CONN_CONFIG(issuercert)) {
+ if(config->verifypeer ||
+ config->verifyhost ||
+ config->issuercert) {
#ifdef USE_GNUTLS_SRP
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP
- && SSL_SET_OPTION(primary.username)
- && !SSL_CONN_CONFIG(verifypeer)
+ if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
+ && ssl_config->primary.username
+ && !config->verifypeer
&& gnutls_cipher_get(session)) {
/* no peer cert, but auth is ok if we have SRP user and cipher and no
peer verify */
@@ -915,7 +896,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
}
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
/* This function will try to verify the peer's certificate and return its
status (trusted, invalid etc.). The value of status should be one or
more of the gnutls_certificate_status_t enumerated elements bitwise
@@ -934,12 +915,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate verification failed. CAfile: %s "
- "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
+ "CRLfile: %s", config->CAfile ? config->CAfile:
"none",
- SSL_SET_OPTION(primary.CRLfile) ?
- SSL_SET_OPTION(primary.CRLfile) : "none");
+ ssl_config->primary.CRLfile ?
+ ssl_config->primary.CRLfile : "none");
return CURLE_PEER_FAILED_VERIFICATION;
}
else
@@ -951,7 +932,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
else
infof(data, " server certificate verification SKIPPED");
- if(SSL_CONN_CONFIG(verifystatus)) {
+ if(config->verifystatus) {
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
gnutls_datum_t status_request;
gnutls_ocsp_resp_t ocsp_resp;
@@ -1062,21 +1043,21 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_t format */
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
- if(SSL_CONN_CONFIG(issuercert)) {
+ if(config->issuercert) {
gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(SSL_CONN_CONFIG(issuercert));
+ issuerp = load_file(config->issuercert);
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
gnutls_x509_crt_deinit(x509_issuer);
unload_file(issuerp);
if(rc <= 0) {
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
- SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
+ config->issuercert?config->issuercert:"none");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_ISSUER_ERROR;
}
infof(data, " server certificate issuer check OK (Issuer Cert: %s)",
- SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
+ config->issuercert?config->issuercert:"none");
}
size = sizeof(certname);
@@ -1139,15 +1120,15 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
#endif
if(!rc) {
- if(SSL_CONN_CONFIG(verifyhost)) {
+ if(config->verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certname, SSL_HOST_DISPNAME());
+ "target host name '%s'", certname, dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, " common name: %s (does not match '%s')",
- certname, SSL_HOST_DISPNAME());
+ certname, dispname);
}
else
infof(data, " common name: %s (matched)", certname);
@@ -1156,7 +1137,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
if(certclock == (time_t)-1) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server cert expiration date verify failed");
*certverifyresult = GNUTLS_CERT_EXPIRED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1167,7 +1148,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
else {
if(certclock < time(NULL)) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate expiration date has passed.");
*certverifyresult = GNUTLS_CERT_EXPIRED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1183,7 +1164,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
if(certclock == (time_t)-1) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server cert activation date verify failed");
*certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1194,7 +1175,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
else {
if(certclock > time(NULL)) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate not activated yet.");
*certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1207,9 +1188,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
infof(data, " server certificate activation date OK");
}
- ptr = SSL_PINNED_PUB_KEY();
- if(ptr) {
- result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
+ if(pinned_key) {
+ result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key);
if(result != CURLE_OK) {
failf(data, "SSL: public key does not match pinned public key");
gnutls_x509_crt_deinit(x509_cert);
@@ -1265,7 +1245,31 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_deinit(x509_cert);
- if(conn->bits.tls_enable_alpn) {
+ return result;
+}
+
+static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ gnutls_session_t session)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ CURLcode result;
+
+ result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
+ connssl->hostname, connssl->dispname,
+ pinned_key);
+ if(result)
+ goto out;
+
+ if(cf->conn->bits.tls_enable_alpn) {
+ gnutls_datum_t proto;
+ int rc;
+
rc = gnutls_alpn_get_selected_protocol(session, &proto);
if(rc == 0) {
infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, proto.size,
@@ -1275,25 +1279,23 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(proto.size == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, proto.data,
ALPN_H2_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(proto.size == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
- conn->ssl[sockindex].state = ssl_connection_complete;
-
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
/* we always unconditionally get the session id here, as even if we
already got it from the cache and asked to use it in the connection, it
might've been rejected and then a new one is in use now and we need to
@@ -1314,9 +1316,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
if(incache) {
/* there was one before in the cache, so instead of risking that the
previous one was rejected, we just kill that and store the new */
@@ -1324,10 +1324,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
/* store this session id */
- result = Curl_ssl_addsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- connect_sessionid, connect_idsize,
- sockindex, &added);
+ result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
+ connect_idsize, &added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(connect_sessionid);
@@ -1339,10 +1337,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
}
+out:
return result;
}
-
/*
* This function is called after the TCP connect has completed. Setup the TLS
* layer and do all necessary magic.
@@ -1353,59 +1351,65 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
'ssl_connect_2_writing' (waiting to be able to write).
*/
static CURLcode
-gtls_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+gtls_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
+ struct ssl_connect_data *connssl = cf->ctx;
int rc;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result = CURLE_OK;
/* Initiate the connection, if not already done */
if(ssl_connect_1 == connssl->connecting_state) {
- rc = gtls_connect_step1(data, conn, sockindex);
- if(rc)
- return rc;
+ rc = gtls_connect_step1(cf, data);
+ if(rc) {
+ result = rc;
+ goto out;
+ }
}
- rc = handshake(data, conn, sockindex, TRUE, nonblocking);
- if(rc)
+ rc = handshake(cf, data, TRUE, nonblocking);
+ if(rc) {
/* handshake() sets its own error message with failf() */
- return rc;
+ result = rc;
+ goto out;
+ }
/* Finish connecting once the handshake is done */
if(ssl_connect_1 == connssl->connecting_state) {
struct ssl_backend_data *backend = connssl->backend;
gnutls_session_t session;
DEBUGASSERT(backend);
- session = backend->session;
- rc = Curl_gtls_verifyserver(data, conn, session, sockindex);
- if(rc)
- return rc;
- conn->recv[sockindex] = gtls_recv;
- conn->send[sockindex] = gtls_send;
+ session = backend->gtls.session;
+ rc = gtls_verifyserver(cf, data, session);
+ if(rc) {
+ result = rc;
+ goto out;
+ }
+ connssl->state = ssl_connection_complete;
}
+out:
*done = ssl_connect_1 == connssl->connecting_state;
- return CURLE_OK;
+ return result;
}
-static CURLcode gtls_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return gtls_connect_common(data, conn, sockindex, TRUE, done);
+ return gtls_connect_common(cf, data, TRUE, done);
}
-static CURLcode gtls_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode gtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = gtls_connect_common(data, conn, sockindex, FALSE, &done);
+ result = gtls_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1414,44 +1418,32 @@ static CURLcode gtls_connect(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static bool gtls_data_pending(const struct connectdata *conn,
- int connindex)
+static bool gtls_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- bool res = FALSE;
- struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_connect_data *ctx = cf->ctx;
- DEBUGASSERT(backend);
-
- if(backend->session &&
- 0 != gnutls_record_check_pending(backend->session))
- res = TRUE;
-
-#ifndef CURL_DISABLE_PROXY
- connssl = &conn->proxy_ssl[connindex];
- backend = connssl->backend;
- DEBUGASSERT(backend);
- if(backend->session &&
- 0 != gnutls_record_check_pending(backend->session))
- res = TRUE;
-#endif
-
- return res;
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->gtls.session &&
+ 0 != gnutls_record_check_pending(ctx->backend->gtls.session))
+ return TRUE;
+ return FALSE;
}
-static ssize_t gtls_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t gtls_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc;
+ (void)data;
DEBUGASSERT(backend);
- rc = gnutls_record_send(backend->session, mem, len);
+ rc = gnutls_record_send(backend->gtls.session, mem, len);
if(rc < 0) {
*curlcode = (rc == GNUTLS_E_AGAIN)
@@ -1464,50 +1456,45 @@ static ssize_t gtls_send(struct Curl_easy *data,
return rc;
}
-static void close_one(struct ssl_connect_data *connssl)
+static void gtls_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+
+ (void) data;
DEBUGASSERT(backend);
- if(backend->session) {
+ if(backend->gtls.session) {
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
- (void)gnutls_record_recv(backend->session, buf, sizeof(buf));
- gnutls_bye(backend->session, GNUTLS_SHUT_WR);
- gnutls_deinit(backend->session);
- backend->session = NULL;
+ (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
+ gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
+ gnutls_deinit(backend->gtls.session);
+ backend->gtls.session = NULL;
}
- if(backend->cred) {
- gnutls_certificate_free_credentials(backend->cred);
- backend->cred = NULL;
+ if(backend->gtls.cred) {
+ gnutls_certificate_free_credentials(backend->gtls.cred);
+ backend->gtls.cred = NULL;
}
#ifdef USE_GNUTLS_SRP
- if(backend->srp_client_cred) {
- gnutls_srp_free_client_credentials(backend->srp_client_cred);
- backend->srp_client_cred = NULL;
+ if(backend->gtls.srp_client_cred) {
+ gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+ backend->gtls.srp_client_cred = NULL;
}
#endif
}
-static void gtls_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- (void) data;
- close_one(&conn->ssl[sockindex]);
-#ifndef CURL_DISABLE_PROXY
- close_one(&conn->proxy_ssl[sockindex]);
-#endif
-}
-
/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int gtls_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_backend_data *backend = connssl->backend;
int retval = 0;
@@ -1520,21 +1507,21 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- gnutls_bye(backend->session, GNUTLS_SHUT_WR);
+ gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
#endif
- if(backend->session) {
+ if(backend->gtls.session) {
ssize_t result;
bool done = FALSE;
char buf[120];
while(!done) {
- int what = SOCKET_READABLE(conn->sock[sockindex],
+ int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- result = gnutls_record_recv(backend->session,
+ result = gnutls_record_recv(backend->gtls.session,
buf, sizeof(buf));
switch(result) {
case 0:
@@ -1564,51 +1551,53 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
done = TRUE;
}
}
- gnutls_deinit(backend->session);
+ gnutls_deinit(backend->gtls.session);
}
- gnutls_certificate_free_credentials(backend->cred);
+ gnutls_certificate_free_credentials(backend->gtls.cred);
#ifdef USE_GNUTLS_SRP
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP
- && SSL_SET_OPTION(primary.username) != NULL)
- gnutls_srp_free_client_credentials(backend->srp_client_cred);
+ if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
+ && ssl_config->primary.username != NULL)
+ gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
#endif
- backend->cred = NULL;
- backend->session = NULL;
+ backend->gtls.cred = NULL;
+ backend->gtls.session = NULL;
return retval;
}
-static ssize_t gtls_recv(struct Curl_easy *data, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
+static ssize_t gtls_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf,
+ size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t ret;
+ (void)data;
DEBUGASSERT(backend);
- ret = gnutls_record_recv(backend->session, buf, buffersize);
+ ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
- return -1;
+ ret = -1;
+ goto out;
}
if(ret == GNUTLS_E_REHANDSHAKE) {
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
proper way" takes a whole lot of work. */
- CURLcode result = handshake(data, conn, num, FALSE, FALSE);
+ CURLcode result = handshake(cf, data, FALSE, FALSE);
if(result)
/* handshake() writes error message on its own */
*curlcode = result;
else
*curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
- return -1;
+ ret = -1;
+ goto out;
}
if(ret < 0) {
@@ -1616,9 +1605,11 @@ static ssize_t gtls_recv(struct Curl_easy *data, /* connection data */
(int)ret, gnutls_strerror((int)ret));
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ ret = -1;
+ goto out;
}
+out:
return ret;
}
@@ -1665,7 +1656,7 @@ static void *gtls_get_internals(struct ssl_connect_data *connssl,
struct ssl_backend_data *backend = connssl->backend;
(void)info;
DEBUGASSERT(backend);
- return backend->session;
+ return backend->gtls.session;
}
const struct Curl_ssl Curl_ssl_gnutls = {
@@ -1688,7 +1679,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_cert_status_request, /* cert_status_request */
gtls_connect, /* connect */
gtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1699,7 +1690,10 @@ const struct Curl_ssl Curl_ssl_gnutls = {
Curl_none_false_start, /* false_start */
gtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ gtls_recv, /* recv decrypted data */
+ gtls_send, /* send data to encrypt */
};
#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index abade73..49c1c47 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -25,15 +25,50 @@
***************************************************************************/
#include "curl_setup.h"
+#include <curl/curl.h>
#ifdef USE_GNUTLS
-#include "urldata.h"
#include <gnutls/gnutls.h>
+
+#ifdef HAVE_GNUTLS_SRP
+/* the function exists */
+#ifdef USE_TLS_SRP
+/* the functionality is not disabled */
+#define USE_GNUTLS_SRP
+#endif
+#endif
+
+struct Curl_easy;
+struct Curl_cfilter;
+struct ssl_primary_config;
+struct ssl_config_data;
+
+struct gtls_instance {
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+#ifdef USE_GNUTLS_SRP
+ gnutls_srp_client_credentials_t srp_client_cred;
+#endif
+};
+
CURLcode
-Curl_gtls_verifyserver(struct Curl_easy *data, struct connectdata *conn,
+gtls_client_init(struct Curl_easy *data,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ const char *hostname,
+ struct gtls_instance *gtls,
+ long *pverifyresult);
+
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_session_t session,
- int sockindex);
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ const char *hostname,
+ const char *dispname,
+ const char *pinned_key);
+
extern const struct Curl_ssl Curl_ssl_gnutls;
#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index fbde897..0b81662 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -61,6 +61,7 @@
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
@@ -155,6 +156,46 @@ static void mbed_debug(void *context, int level, const char *f_name,
#else
#endif
+static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen)
+{
+ struct Curl_cfilter *cf = bio;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
+ blen, (int)nwritten, result)); */
+ if(nwritten < 0 && CURLE_AGAIN == result) {
+ nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+ return (int)nwritten;
+}
+
+static int bio_cf_read(void *bio, unsigned char *buf, size_t blen)
+{
+ struct Curl_cfilter *cf = bio;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
+ blen, (int)nread, result)); */
+ if(nread < 0 && CURLE_AGAIN == result) {
+ nread = MBEDTLS_ERR_SSL_WANT_READ;
+ }
+ return (int)nread;
+}
+
/*
* profile
*/
@@ -181,9 +222,6 @@ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
-static Curl_recv mbed_recv;
-static Curl_send mbed_send;
-
static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
{
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
@@ -216,11 +254,11 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
}
static CURLcode
-set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
@@ -228,8 +266,8 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
#endif
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
CURLcode result = CURLE_OK;
DEBUGASSERT(backend);
@@ -268,31 +306,29 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile);
- const char * const hostname = SSL_HOST_NAME();
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- const long int port = SSL_HOST_PORT();
-#endif
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ const char * const ssl_capath = conn_config->CApath;
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+ const char *hostname = connssl->hostname;
int ret = -1;
char errorbuf[128];
DEBUGASSERT(backend);
- if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) ||
- (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) {
+ if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
+ (conn_config->version == CURL_SSLVERSION_SSLv3)) {
failf(data, "Not supported SSL version");
return CURLE_NOT_BUILT_IN;
}
@@ -416,7 +452,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
- SSL_SET_OPTION(key), -ret, errorbuf);
+ ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
}
@@ -424,23 +460,23 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* Load the client private key */
mbedtls_pk_init(&backend->pk);
- if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
- if(SSL_SET_OPTION(key)) {
+ if(ssl_config->key || ssl_config->key_blob) {
+ if(ssl_config->key) {
#ifdef MBEDTLS_FS_IO
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
- ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
- SSL_SET_OPTION(key_passwd),
+ ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+ ssl_config->key_passwd,
mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
#else
- ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
- SSL_SET_OPTION(key_passwd));
+ ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+ ssl_config->key_passwd);
#endif
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
- SSL_SET_OPTION(key), -ret, errorbuf);
+ ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
#else
@@ -449,10 +485,10 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
}
else {
- const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob);
+ const struct curl_blob *ssl_key_blob = ssl_config->key_blob;
const unsigned char *key_data =
(const unsigned char *)ssl_key_blob->data;
- const char *passwd = SSL_SET_OPTION(key_passwd);
+ const char *passwd = ssl_config->key_passwd;
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
(const unsigned char *)passwd,
@@ -505,7 +541,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#endif
- infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port);
+ infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@@ -527,7 +563,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_conf_cert_profile(&backend->config,
&mbedtls_x509_crt_profile_fr);
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if MBEDTLS_VERSION_NUMBER < 0x03000000
@@ -541,7 +577,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -555,9 +591,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
- mbedtls_ssl_set_bio(&backend->ssl, &conn->sock[sockindex],
- mbedtls_net_send,
- mbedtls_net_recv,
+ mbedtls_ssl_set_bio(&backend->ssl, cf, bio_cf_write, bio_cf_read,
NULL /* rev_timeout() */);
mbedtls_ssl_conf_ciphersuites(&backend->config,
@@ -574,13 +608,11 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &old_session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@@ -600,7 +632,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
NULL);
#endif
- if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
+ if(ssl_config->key || ssl_config->key_blob) {
mbedtls_ssl_conf_own_cert(&backend->config,
&backend->clicert, &backend->pk);
}
@@ -616,7 +648,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char **p = &backend->protocols[0];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2)
@@ -664,20 +696,19 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const mbedtls_x509_crt *peercert;
- const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
DEBUGASSERT(backend);
- conn->recv[sockindex] = mbed_recv;
- conn->send[sockindex] = mbed_send;
-
ret = mbedtls_ssl_handshake(&backend->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
@@ -701,11 +732,11 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
- if(!SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifyhost)
/* Ignore hostname errors if verifyhost is disabled */
ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
- if(ret && SSL_CONN_CONFIG(verifypeer)) {
+ if(ret && conn_config->verifypeer) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
@@ -813,7 +844,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
if(next_protocol) {
@@ -821,19 +852,19 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(!strncmp(next_protocol, ALPN_H2, ALPN_H2_LENGTH) &&
!next_protocol[ALPN_H2_LENGTH]) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
!next_protocol[ALPN_HTTP_1_1_LENGTH]) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else {
infof(data, VTLS_INFOF_NO_ALPN);
}
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -845,21 +876,20 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode retcode = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
@@ -879,12 +909,11 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
- sockindex))
+ if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex, &added);
+ retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
+ 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);
@@ -901,17 +930,16 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static ssize_t mbed_send(struct Curl_easy *data, int sockindex,
+static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *mem, size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int ret = -1;
+ (void)data;
DEBUGASSERT(backend);
-
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
@@ -928,14 +956,13 @@ static void mbedtls_close_all(struct Curl_easy *data)
(void)data;
}
-static void mbedtls_close(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char buf[32];
- (void) data;
+ (void)data;
DEBUGASSERT(backend);
/* Maybe the server has already sent a close notify alert.
@@ -956,16 +983,16 @@ static void mbedtls_close(struct Curl_easy *data,
#endif /* THREADING_SUPPORT */
}
-static ssize_t mbed_recv(struct Curl_easy *data, int num,
+static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int ret = -1;
ssize_t len = -1;
+ (void)data;
DEBUGASSERT(backend);
ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
@@ -1048,15 +1075,13 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
}
static CURLcode
-mbed_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode retcode;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1075,7 +1100,7 @@ mbed_connect_common(struct Curl_easy *data,
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEDOUT;
}
- retcode = mbed_connect_step1(data, conn, sockindex);
+ retcode = mbed_connect_step1(cf, data);
if(retcode)
return retcode;
}
@@ -1130,7 +1155,7 @@ mbed_connect_common(struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- retcode = mbed_connect_step2(data, conn, sockindex);
+ retcode = mbed_connect_step2(cf, data);
if(retcode || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1140,15 +1165,13 @@ mbed_connect_common(struct Curl_easy *data,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- retcode = mbed_connect_step3(data, conn, sockindex);
+ retcode = mbed_connect_step3(cf, data);
if(retcode)
return retcode;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = mbed_recv;
- conn->send[sockindex] = mbed_send;
*done = TRUE;
}
else
@@ -1160,21 +1183,21 @@ mbed_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode mbedtls_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return mbed_connect_common(data, conn, sockindex, TRUE, done);
+ return mbed_connect_common(cf, data, TRUE, done);
}
-static CURLcode mbedtls_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode retcode;
bool done = FALSE;
- retcode = mbed_connect_common(data, conn, sockindex, FALSE, &done);
+ retcode = mbed_connect_common(cf, data, FALSE, &done);
if(retcode)
return retcode;
@@ -1197,13 +1220,14 @@ static void mbedtls_cleanup(void)
(void)Curl_mbedtlsthreadlock_thread_cleanup();
}
-static bool mbedtls_data_pending(const struct connectdata *conn,
- int sockindex)
+static bool mbedtls_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return mbedtls_ssl_get_bytes_avail(&ctx->backend->ssl) != 0;
}
static CURLcode mbedtls_sha256sum(const unsigned char *input,
@@ -1242,7 +1266,8 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_SSL_CTX,
+ SSLSUPP_SSL_CTX |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -1256,7 +1281,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_cert_status_request, /* cert_status_request */
mbedtls_connect, /* connect */
mbedtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
@@ -1267,7 +1292,10 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_false_start, /* false_start */
mbedtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ mbed_recv, /* recv decrypted data */
+ mbed_send, /* send data to encrypt */
};
#endif /* USE_MBEDTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
index 3971e69..7d019ed 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
@@ -26,13 +26,12 @@
#if defined(USE_MBEDTLS) && \
((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)))
+ defined(USE_THREADS_WIN32))
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
# include <pthread.h>
# define MBEDTLS_MUTEX_T pthread_mutex_t
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
-# include <process.h>
+#elif defined(USE_THREADS_WIN32)
# define MBEDTLS_MUTEX_T HANDLE
#endif
@@ -60,7 +59,7 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_init(&mutex_buf[i], NULL))
return 0; /* pthread_mutex_init failed */
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
mutex_buf[i] = CreateMutex(0, FALSE, 0);
if(mutex_buf[i] == 0)
return 0; /* CreateMutex failed */
@@ -81,7 +80,7 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_destroy(&mutex_buf[i]))
return 0; /* pthread_mutex_destroy failed */
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(!CloseHandle(mutex_buf[i]))
return 0; /* CloseHandle failed */
#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
@@ -101,7 +100,7 @@ int Curl_mbedtlsthreadlock_lock_function(int n)
"Error: mbedtlsthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_lock_function failed\n"));
@@ -121,7 +120,7 @@ int Curl_mbedtlsthreadlock_unlock_function(int n)
"Error: mbedtlsthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_unlock failed */
}
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(!ReleaseMutex(mutex_buf[n])) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_unlock_function failed\n"));
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
index 3a50d03..22e8725 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
+++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
@@ -29,7 +29,7 @@
#ifdef USE_MBEDTLS
#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))
+ defined(USE_THREADS_WIN32)
int Curl_mbedtlsthreadlock_thread_setup(void);
int Curl_mbedtlsthreadlock_thread_cleanup(void);
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index 12cf618..03694d2 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -39,6 +39,7 @@
#include "strcase.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "llist.h"
#include "multiif.h"
#include "curl_printf.h"
@@ -68,7 +69,6 @@
#include <ocsp.h>
#endif
-#include "strcase.h"
#include "warnless.h"
#include "x509asn1.h"
@@ -696,17 +696,18 @@ fail:
return CURLE_SSL_CRL_BADFILE;
}
-static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, char *key_file)
+static CURLcode nss_load_key(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *key_file)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
PK11SlotInfo *slot, *tmp;
SECStatus status;
CURLcode result;
- struct ssl_connect_data *ssl = conn->ssl;
-
- (void)sockindex; /* unused */
- result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
+ (void)data;
+ result = nss_create_object(connssl, CKO_PRIVATE_KEY, key_file, FALSE);
if(result) {
PR_SetError(SEC_ERROR_BAD_KEY, 0);
return result;
@@ -725,7 +726,7 @@ static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
return CURLE_SSL_CERTPROBLEM;
}
- status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
+ status = PK11_Authenticate(slot, PR_TRUE, ssl_config->key_passwd);
PK11_FreeSlot(slot);
return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
@@ -747,13 +748,15 @@ static int display_error(struct Curl_easy *data, PRInt32 err,
return 0; /* The caller will print a generic error */
}
-static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, char *cert_file, char *key_file)
+static CURLcode cert_stuff(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *cert_file, char *key_file)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
if(cert_file) {
- result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
+ result = nss_load_cert(connssl, cert_file, PR_FALSE);
if(result) {
const PRErrorCode err = PR_GetError();
if(!display_error(data, err, cert_file)) {
@@ -767,10 +770,10 @@ static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
if(key_file || (is_file(cert_file))) {
if(key_file)
- result = nss_load_key(data, conn, sockindex, key_file);
+ result = nss_load_key(cf, data, key_file);
else
/* In case the cert file also has the key */
- result = nss_load_key(data, conn, sockindex, cert_file);
+ result = nss_load_key(cf, data, cert_file);
if(result) {
const PRErrorCode err = PR_GetError();
if(!display_error(data, err, key_file)) {
@@ -800,11 +803,14 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
PRBool isServer)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_easy *data = connssl->backend->data;
+ DEBUGASSERT(data);
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(SSL_CONN_CONFIG(verifystatus)) {
+ if(conn_config->verifystatus) {
SECStatus cacheResult;
const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
@@ -830,7 +836,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
}
#endif
- if(!SSL_CONN_CONFIG(verifypeer)) {
+ if(!conn_config->verifypeer) {
infof(data, "skipping SSL peer certificate verification");
return SECSuccess;
}
@@ -843,13 +849,16 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
*/
static void HandshakeCallback(PRFileDesc *sock, void *arg)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->backend->data;
+ struct connectdata *conn = cf->conn;
unsigned int buflenmax = 50;
unsigned char buf[50];
unsigned int buflen;
SSLNextProtoState state;
+ DEBUGASSERT(data);
if(!conn->bits.tls_enable_alpn) {
return;
}
@@ -879,13 +888,13 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
#ifdef USE_HTTP2
if(buflen == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(buflen == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
/* This callback might get called when PR_Recv() is used within
@@ -893,7 +902,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
* be any "bundle" associated with the connection anymore.
*/
if(conn->bundle)
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
@@ -1064,15 +1073,20 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->backend->data;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config;
PRErrorCode err = PR_GetError();
CERTCertificate *cert;
+ DEBUGASSERT(data);
+ ssl_config = Curl_ssl_cf_get_config(cf, data);
/* remember the cert verification result */
- SSL_SET_OPTION_LVALUE(certverifyresult) = err;
+ ssl_config->certverifyresult = err;
- if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
+ if(err == SSL_ERROR_BAD_CERT_DOMAIN && !conn_config->verifyhost)
/* we are asked not to verify the host name */
return SECSuccess;
@@ -1549,13 +1563,14 @@ static void nss_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int nss_check_cxn(struct connectdata *conn)
+static int nss_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int rc;
char buf;
+ (void)data;
DEBUGASSERT(backend);
rc =
@@ -1612,41 +1627,20 @@ static void close_one(struct ssl_connect_data *connssl)
/*
* This function is called when an SSL connection is closed.
*/
-static void nss_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void nss_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-#ifndef CURL_DISABLE_PROXY
- struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
-#endif
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void)data;
-
DEBUGASSERT(backend);
-#ifndef CURL_DISABLE_PROXY
- DEBUGASSERT(connssl_proxy->backend != NULL);
-#endif
- if(backend->handle
-#ifndef CURL_DISABLE_PROXY
- || connssl_proxy->backend->handle
-#endif
- ) {
+ if(backend->handle) {
/* NSS closes the socket we previously handed to it, so we must mark it
as closed to avoid double close */
- fake_sclose(conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
+ fake_sclose(cf->conn->sock[cf->sockindex]);
+ cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
}
-#ifndef CURL_DISABLE_PROXY
- if(backend->handle)
- /* nss_close(connssl) will transitively close also
- connssl_proxy->backend->handle if both are used. Clear it to avoid
- a double close leading to crash. */
- connssl_proxy->backend->handle = NULL;
-
- close_one(connssl_proxy);
-#endif
close_one(connssl);
}
@@ -1680,15 +1674,13 @@ static bool is_cc_error(PRInt32 err)
}
}
-static Curl_recv nss_recv;
-static Curl_send nss_send;
-
-static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode nss_load_ca_certificates(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- const char *cafile = SSL_CONN_CONFIG(CAfile);
- const char *capath = SSL_CONN_CONFIG(CApath);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const char *cafile = conn_config->CAfile;
+ const char *capath = conn_config->CApath;
bool use_trust_module;
CURLcode result = CURLE_OK;
@@ -1723,7 +1715,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
PR_Unlock(nss_trustload_lock);
if(cafile)
- result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
+ result = nss_load_cert(connssl, cafile, PR_TRUE);
if(result)
return result;
@@ -1747,7 +1739,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
+ if(CURLE_OK != nss_load_cert(connssl, fullpath, PR_TRUE))
/* This is purposefully tolerant of errors so non-PEM files can
* be in the same directory */
infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
@@ -1808,12 +1800,13 @@ static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
}
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct Curl_easy *data,
- struct connectdata *conn)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result;
- const long min = SSL_CONN_CONFIG(version);
- const long max = SSL_CONN_CONFIG(version_max);
+ const long min = conn_config->version;
+ const long max = conn_config->version_max;
SSLVersionRange vrange;
switch(min) {
@@ -1848,10 +1841,11 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
return CURLE_OK;
}
-static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
+static CURLcode nss_fail_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode curlerr)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
@@ -1876,10 +1870,11 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
}
/* Switch the SSL socket into blocking or non-blocking mode. */
-static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
+static CURLcode nss_set_blocking(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking)
{
+ struct ssl_connect_data *connssl = cf->ctx;
PRSocketOptionData sock_opt;
struct ssl_backend_data *backend = connssl->backend;
@@ -1889,22 +1884,27 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
sock_opt.value.non_blocking = !blocking;
if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
- return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
+ return nss_fail_connect(cf, data, CURLE_SSL_CONNECT_ERROR);
return CURLE_OK;
}
-static CURLcode nss_setup_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
PRFileDesc *model = NULL;
PRFileDesc *nspr_io = NULL;
PRFileDesc *nspr_io_stub = NULL;
PRBool ssl_no_cache;
PRBool ssl_cbc_random_iv;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
CURLcode result;
bool second_layer = FALSE;
SSLVersionRange sslver_supported;
@@ -1920,7 +1920,10 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
SSL_LIBRARY_VERSION_TLS_1_0
#endif
};
- char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ const char *hostname = connssl->hostname;
+ char *snihost;
+
+ snihost = Curl_ssl_snihost(data, hostname, NULL);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -1965,13 +1968,13 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
goto error;
/* do not use SSL cache if disabled or we are not going to verify peer */
- ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
- && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
+ ssl_no_cache = (ssl_config->primary.sessionid
+ && conn_config->verifypeer) ? PR_FALSE : PR_TRUE;
if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
goto error;
/* enable/disable the requested SSL version(s) */
- if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
+ if(nss_init_sslver(&sslver, cf, data) != CURLE_OK)
goto error;
if(SSL_VersionRangeGetSupported(ssl_variant_stream,
&sslver_supported) != SECSuccess)
@@ -1990,7 +1993,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
goto error;
- ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
+ ssl_cbc_random_iv = !ssl_config->enable_beast;
#ifdef SSL_CBC_RANDOM_IV
/* unless the user explicitly asks to allow the protocol vulnerability, we
use the work-around */
@@ -2002,33 +2005,33 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in");
#endif
- if(SSL_CONN_CONFIG(cipher_list)) {
- if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
+ if(conn_config->cipher_list) {
+ if(set_ciphers(data, model, conn_config->cipher_list) != SECSuccess) {
result = CURLE_SSL_CIPHER;
goto error;
}
}
- if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifypeer && conn_config->verifyhost)
infof(data, "WARNING: ignoring value of ssl.verifyhost");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
* verify peer */
- if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
+ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, cf) != SECSuccess)
goto error;
/* not checked yet */
- SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
+ ssl_config->certverifyresult = 0;
- if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
+ if(SSL_BadCertHook(model, BadCertHandler, cf) != SECSuccess)
goto error;
- if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
+ if(SSL_HandshakeCallback(model, HandshakeCallback, cf) != SECSuccess)
goto error;
{
- const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
- if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
+ const CURLcode rv = nss_load_ca_certificates(cf, data);
+ if((rv == CURLE_SSL_CACERT_BADFILE) && !conn_config->verifypeer)
/* not a fatal error because we are not going to verify the peer */
infof(data, "WARNING: CA certificates failed to load");
else if(rv) {
@@ -2037,25 +2040,25 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
}
}
- if(SSL_SET_OPTION(primary.CRLfile)) {
- const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile));
+ if(ssl_config->primary.CRLfile) {
+ const CURLcode rv = nss_load_crl(ssl_config->primary.CRLfile);
if(rv) {
result = rv;
goto error;
}
- infof(data, " CRLfile: %s", SSL_SET_OPTION(primary.CRLfile));
+ infof(data, " CRLfile: %s", ssl_config->primary.CRLfile);
}
- if(SSL_SET_OPTION(primary.clientcert)) {
- char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
+ if(ssl_config->primary.clientcert) {
+ char *nickname = dup_nickname(data, ssl_config->primary.clientcert);
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
backend->obj_clicert = NULL;
}
else {
- CURLcode rv = cert_stuff(data, conn, sockindex,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key));
+ CURLcode rv = cert_stuff(cf, data,
+ ssl_config->primary.clientcert,
+ ssl_config->key);
if(rv) {
/* failf() is already done in cert_stuff() */
result = rv;
@@ -2075,17 +2078,19 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
goto error;
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *proxy_backend;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(proxy_backend);
- DEBUGASSERT(proxy_backend->handle);
- nspr_io = proxy_backend->handle;
+ /* Is there an SSL filter "in front" of us or are we writing directly
+ * to the socket? */
+ if(connssl_next) {
+ /* The filter should be connected by now, with full handshake */
+ DEBUGASSERT(connssl_next->backend->handle);
+ DEBUGASSERT(ssl_connection_complete == connssl_next->state);
+ /* We tell our NSS instance to use do IO with the 'next' NSS
+ * instance. This NSS instance will take ownership of the next
+ * one, including its destruction. We therefore need to `disown`
+ * the next filter's handle, once import succeeds. */
+ nspr_io = connssl_next->backend->handle;
second_layer = TRUE;
}
-#endif
else {
/* wrap OS file descriptor by NSPR's file descriptor abstraction */
nspr_io = PR_ImportTCPSocket(sockfd);
@@ -2122,14 +2127,16 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
PR_Close(model); /* We don't need this any more */
model = NULL;
+ if(connssl_next) /* steal the NSS handle we just imported successfully */
+ connssl_next->backend->handle = NULL;
/* This is the password associated with the cert that we're using */
- if(SSL_SET_OPTION(key_passwd)) {
- SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
+ if(ssl_config->key_passwd) {
+ SSL_SetPKCS11PinArg(backend->handle, ssl_config->key_passwd);
}
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(SSL_CONN_CONFIG(verifystatus)) {
+ if(conn_config->verifystatus) {
if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess)
goto error;
@@ -2137,8 +2144,9 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
#endif
#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
+ if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN,
+ cf->conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE)
+ != SECSuccess)
goto error;
#endif
@@ -2155,14 +2163,14 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
#endif
#if defined(SSL_ENABLE_ALPN)
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
protocols[cur++] = ALPN_H2_LENGTH;
@@ -2199,14 +2207,16 @@ error:
if(model)
PR_Close(model);
- return nss_fail_connect(connssl, data, result);
+ return nss_fail_connect(cf, data, result);
}
-static CURLcode nss_do_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode nss_do_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout;
@@ -2226,9 +2236,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
/* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN;
- else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN)
+ else if(ssl_config->certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
result = CURLE_PEER_FAILED_VERIFICATION;
- else if(SSL_SET_OPTION(certverifyresult) != 0)
+ else if(ssl_config->certverifyresult)
result = CURLE_PEER_FAILED_VERIFICATION;
goto error;
}
@@ -2237,9 +2247,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(result)
goto error;
- if(SSL_CONN_CONFIG(issuercert)) {
+ if(conn_config->issuercert) {
SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
+ char *nickname = dup_nickname(data, conn_config->issuercert);
if(nickname) {
/* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(backend->handle, nickname);
@@ -2256,7 +2266,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
}
}
- result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY());
+ result = cmp_peer_pubkey(connssl, Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result)
/* status already printed */
goto error;
@@ -2264,14 +2276,14 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
return CURLE_OK;
error:
- return nss_fail_connect(connssl, data, result);
+ return nss_fail_connect(cf, data, result);
}
-static CURLcode nss_connect_common(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode nss_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool *done)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
const bool blocking = (done == NULL);
CURLcode result;
@@ -2282,7 +2294,7 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
}
if(connssl->connecting_state == ssl_connect_1) {
- result = nss_setup_connect(data, conn, sockindex);
+ result = nss_setup_connect(cf, data);
if(result)
/* we do not expect CURLE_AGAIN from nss_setup_connect() */
return result;
@@ -2291,11 +2303,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
}
/* enable/disable blocking mode before handshake */
- result = nss_set_blocking(connssl, data, blocking);
+ result = nss_set_blocking(cf, data, blocking);
if(result)
return result;
- result = nss_do_connect(data, conn, sockindex);
+ result = nss_do_connect(cf, data);
switch(result) {
case CURLE_OK:
break;
@@ -2311,7 +2323,7 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
if(blocking) {
/* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
- result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
+ result = nss_set_blocking(cf, data, /* blocking */ FALSE);
if(result)
return result;
}
@@ -2320,8 +2332,6 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
*done = TRUE;
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = nss_recv;
- conn->send[sockindex] = nss_send;
/* ssl_connect_done is never used outside, go back to the initial state */
connssl->connecting_state = ssl_connect_1;
@@ -2329,30 +2339,30 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode nss_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode nss_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- return nss_connect_common(data, conn, sockindex, /* blocking */ NULL);
+ return nss_connect_common(cf, data, /* blocking */ NULL);
}
-static CURLcode nss_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode nss_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return nss_connect_common(data, conn, sockindex, done);
+ return nss_connect_common(cf, data, done);
}
-static ssize_t nss_send(struct Curl_easy *data, /* transfer */
- int sockindex, /* socketindex */
+static ssize_t nss_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
const void *mem, /* send this data */
size_t len, /* amount to write */
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc;
+ (void)data;
DEBUGASSERT(backend);
/* The SelectClientCert() hook uses this for infof() and failf() but the
@@ -2383,17 +2393,17 @@ static ssize_t nss_send(struct Curl_easy *data, /* transfer */
return rc; /* number of bytes */
}
-static ssize_t nss_recv(struct Curl_easy *data, /* transfer */
- int sockindex, /* socketindex */
+static ssize_t nss_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread;
+ (void)data;
DEBUGASSERT(backend);
/* The SelectClientCert() hook uses this for infof() and failf() but the
@@ -2498,6 +2508,25 @@ static void *nss_get_internals(struct ssl_connect_data *connssl,
return backend->handle;
}
+static bool nss_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(!connssl->backend->data)
+ connssl->backend->data = data;
+ return TRUE;
+}
+
+static void nss_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(connssl->backend->data == data)
+ connssl->backend->data = NULL;
+}
+
const struct Curl_ssl Curl_ssl_nss = {
{ CURLSSLBACKEND_NSS, "nss" }, /* info */
@@ -2519,7 +2548,7 @@ const struct Curl_ssl Curl_ssl_nss = {
nss_cert_status_request, /* cert_status_request */
nss_connect, /* connect */
nss_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
nss_get_internals, /* get_internals */
nss_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2530,8 +2559,11 @@ const struct Curl_ssl Curl_ssl_nss = {
Curl_none_engines_list, /* engines_list */
nss_false_start, /* false_start */
nss_sha256sum, /* sha256sum */
- NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ nss_attach_data, /* associate_connection */
+ nss_detach_data, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ nss_recv, /* recv decrypted data */
+ nss_send, /* send data to encrypt */
};
#endif /* USE_NSS */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 0dc695d..c5085be 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -55,6 +55,7 @@
#include "slist.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "vauth/vauth.h"
#include "keylog.h"
#include "strcase.h"
@@ -261,6 +262,28 @@
#define HAVE_OPENSSL_VERSION
#endif
+/*
+ * Whether the OpenSSL version has the API needed to support sharing an
+ * X509_STORE between connections. The API is:
+ * * `X509_STORE_up_ref` -- Introduced: OpenSSL 1.1.0.
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* OpenSSL >= 1.1.0 */
+#define HAVE_SSL_X509_STORE_SHARE
+#endif
+
+/* FIXME: On a specific machine using LCC 1.23, OpenSSL 2.0.0
+ * is found but does not seem to have X509_STORE_up_ref. */
+#if defined(__LCC__) && defined(__EDG__) && (__LCC__ == 123)
+#undef HAVE_SSL_X509_STORE_SHARE
+#endif
+
+/* What API version do we use? */
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
+#else /* !LIBRESSL_VERSION_NUMBER */
+#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#endif /* !LIBRESSL_VERSION_NUMBER */
+
struct ssl_backend_data {
struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
using sockindex 0 */
@@ -268,12 +291,21 @@ struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
X509* server_cert;
+ CURLcode io_result; /* result of last BIO cfilter operation */
#ifndef HAVE_KEYLOG_CALLBACK
/* Set to true once a valid keylog entry has been created to avoid dupes. */
bool keylog_done;
#endif
};
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+struct multi_ssl_backend_data {
+ char *CAfile; /* CAfile path used to generate X509 store */
+ X509_STORE *store; /* cached X509 store or NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
#define push_certinfo(_label, _num) \
do { \
long info_len = BIO_get_mem_data(mem, &ptr); \
@@ -612,9 +644,160 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
#ifdef USE_OPENSSL
-static bool ossl_associate_connection(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex);
+#if USE_PRE_1_1_API
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
+#define BIO_set_init(x,v) ((x)->init=(v))
+#define BIO_get_data(x) ((x)->ptr)
+#define BIO_set_data(x,v) ((x)->ptr=(v))
+#endif
+#define BIO_get_shutdown(x) ((x)->shutdown)
+#define BIO_set_shutdown(x,v) ((x)->shutdown=(v))
+#endif /* USE_PRE_1_1_API */
+
+static int bio_cf_create(BIO *bio)
+{
+ BIO_set_shutdown(bio, 1);
+ BIO_set_init(bio, 1);
+#if USE_PRE_1_1_API
+ bio->num = -1;
+#endif
+ BIO_set_data(bio, NULL);
+ return 1;
+}
+
+static int bio_cf_destroy(BIO *bio)
+{
+ if(!bio)
+ return 0;
+ return 1;
+}
+
+static long bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ long ret = 1;
+
+ (void)cf;
+ (void)ptr;
+ switch(cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)BIO_get_shutdown(bio);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ BIO_set_shutdown(bio, (int)num);
+ break;
+ case BIO_CTRL_FLUSH:
+ /* we do no delayed writes, but if we ever would, this
+ * needs to trigger it. */
+ ret = 1;
+ break;
+ case BIO_CTRL_DUP:
+ ret = 1;
+ break;
+#ifdef BIO_CTRL_EOF
+ case BIO_CTRL_EOF:
+ /* EOF has been reached on input? */
+ return (!cf->next || !cf->next->connected);
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result = CURLE_SEND_ERROR;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
+ blen, (int)nwritten, result)); */
+ BIO_clear_retry_flags(bio);
+ connssl->backend->io_result = result;
+ if(nwritten < 0) {
+ if(CURLE_AGAIN == result)
+ BIO_set_retry_write(bio);
+ }
+ return (int)nwritten;
+}
+
+static int bio_cf_in_read(BIO *bio, char *buf, int blen)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result = CURLE_RECV_ERROR;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
+ blen, (int)nread, result)); */
+ BIO_clear_retry_flags(bio);
+ connssl->backend->io_result = result;
+ if(nread < 0) {
+ if(CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ }
+ return (int)nread;
+}
+
+static BIO_METHOD *bio_cf_method = NULL;
+
+#if USE_PRE_1_1_API
+
+static BIO_METHOD bio_cf_meth_1_0 = {
+ BIO_TYPE_MEM,
+ "OpenSSL CF BIO",
+ bio_cf_out_write,
+ bio_cf_in_read,
+ NULL, /* puts is never called */
+ NULL, /* gets is never called */
+ bio_cf_ctrl,
+ bio_cf_create,
+ bio_cf_destroy,
+ NULL
+};
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = &bio_cf_meth_1_0;
+}
+
+#define bio_cf_free_methods() Curl_nop_stmt
+
+#else
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO");
+ BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
+ BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
+ BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
+ BIO_meth_set_create(bio_cf_method, &bio_cf_create);
+ BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
+}
+
+static void bio_cf_free_methods(void)
+{
+ BIO_meth_free(bio_cf_method);
+}
+
+#endif
+
+
+static bool ossl_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
/*
* Number of bytes to read from the random number seed file. This must be
@@ -713,12 +896,25 @@ static const char *SSL_ERROR_to_str(int err)
}
}
+static size_t ossl_version(char *buffer, size_t size);
+
/* Return error string for last OpenSSL error
*/
static char *ossl_strerror(unsigned long error, char *buf, size_t size)
{
- if(size)
+ size_t len;
+ DEBUGASSERT(size);
+ *buf = '\0';
+
+ len = ossl_version(buf, size);
+ DEBUGASSERT(len < (size - 2));
+ if(len < (size - 2)) {
+ buf += len;
+ size -= (len + 2);
+ *buf++ = ':';
+ *buf++ = ' ';
*buf = '\0';
+ }
#ifdef OPENSSL_IS_BORINGSSL
ERR_error_string_n((uint32_t)error, buf, size);
@@ -726,7 +922,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
ERR_error_string_n(error, buf, size);
#endif
- if(size > 1 && !*buf) {
+ if(!*buf) {
strncpy(buf, (error ? "Unknown error" : "No error"), size);
buf[size - 1] = '\0';
}
@@ -746,16 +942,16 @@ static int ossl_get_ssl_data_index(void)
return ssl_ex_data_data_index;
}
-/* Return an extra data index for the connection data.
+/* Return an extra data index for the associated Curl_cfilter instance.
* This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
*/
-static int ossl_get_ssl_conn_index(void)
+static int ossl_get_ssl_cf_index(void)
{
- static int ssl_ex_data_conn_index = -1;
- if(ssl_ex_data_conn_index < 0) {
- ssl_ex_data_conn_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ static int ssl_ex_data_cf_index = -1;
+ if(ssl_ex_data_cf_index < 0) {
+ ssl_ex_data_cf_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
}
- return ssl_ex_data_conn_index;
+ return ssl_ex_data_cf_index;
}
/* Return an extra data index for the sockindex.
@@ -1580,10 +1776,11 @@ static int ossl_init(void)
OpenSSL_add_all_algorithms();
#endif
+ bio_cf_init_methods();
Curl_tls_keylog_open();
/* Initialize the extra data indexes */
- if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_conn_index() < 0 ||
+ if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_cf_index() < 0 ||
ossl_get_ssl_sockindex_index() < 0 || ossl_get_proxy_index() < 0)
return 0;
@@ -1625,6 +1822,7 @@ static void ossl_cleanup(void)
#endif
Curl_tls_keylog_close();
+ bio_cf_free_methods();
}
/*
@@ -1635,15 +1833,16 @@ static void ossl_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int ossl_check_cxn(struct connectdata *conn)
+static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
/* SSL_peek takes data out of the raw recv buffer without peeking so we use
recv MSG_PEEK instead. Bug #795 */
#ifdef MSG_PEEK
char buf;
ssize_t nread;
- nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
- (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
+ nread = recv((RECV_TYPE_ARG1)cf->conn->sock[cf->sockindex],
+ (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1,
+ (RECV_TYPE_ARG4)MSG_PEEK);
if(nread == 0)
return 0; /* connection has been closed */
if(nread == 1)
@@ -1676,6 +1875,7 @@ static int ossl_check_cxn(struct connectdata *conn)
return 0; /* connection has been closed */
}
#endif
+ (void)data;
return -1; /* connection status unknown */
}
@@ -1768,33 +1968,28 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
return list;
}
-#define set_logger(conn, data) \
- conn->ssl[0].backend->logger = data
+#define set_logger(connssl, data) \
+ connssl->backend->logger = data
-static void ossl_closeone(struct Curl_easy *data,
- struct connectdata *conn,
- struct ssl_connect_data *connssl)
+static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
if(backend->handle) {
- char buf[32];
- set_logger(conn, data);
- /*
- * The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make
- * sure the socket is not closed before calling OpenSSL functions that
- * will use it.
- */
- DEBUGASSERT(conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD);
+ set_logger(connssl, data);
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
+ if(cf->next && cf->next->connected) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
- (void)SSL_shutdown(backend->handle);
- SSL_set_connect_state(backend->handle);
+ (void)SSL_shutdown(backend->handle);
+ SSL_set_connect_state(backend->handle);
+ }
SSL_free(backend->handle);
backend->handle = NULL;
@@ -1806,30 +2001,18 @@ static void ossl_closeone(struct Curl_easy *data,
}
/*
- * This function is called when an SSL connection is closed.
- */
-static void ossl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- ossl_closeone(data, conn, &conn->ssl[sockindex]);
-#ifndef CURL_DISABLE_PROXY
- ossl_closeone(data, conn, &conn->proxy_ssl[sockindex]);
-#endif
-}
-
-/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int ossl_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int ossl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
to be at least 256 bytes long. */
unsigned long sslerror;
- ssize_t nread;
+ int nread;
int buffsize;
int err;
bool done = FALSE;
@@ -1851,15 +2034,15 @@ static int ossl_shutdown(struct Curl_easy *data,
if(backend->handle) {
buffsize = (int)sizeof(buf);
while(!done && loop--) {
- int what = SOCKET_READABLE(conn->sock[sockindex],
+ int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
ERR_clear_error();
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
- err = SSL_get_error(backend->handle, (int)nread);
+ nread = SSL_read(backend->handle, buf, buffsize);
+ err = SSL_get_error(backend->handle, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -2017,9 +2200,18 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
- const char * const hostname = SSL_HOST_NAME();
- const char * const dispname = SSL_HOST_DISPNAME();
- size_t hostlen = strlen(hostname);
+ const char *hostname, *dispname;
+ int port;
+ size_t hostlen;
+
+ (void)conn;
+ Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port);
+ hostlen = strlen(hostname);
+
+#ifndef ENABLE_IPV6
+ /* Silence compiler warnings for unused params */
+ (void) conn;
+#endif
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip &&
@@ -2195,9 +2387,10 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
-static CURLcode verifystatus(struct Curl_easy *data,
- struct ssl_connect_data *connssl)
+static CURLcode verifystatus(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
int i, ocsp_status;
unsigned char *status;
const unsigned char *p;
@@ -2478,18 +2671,24 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
char unknown[32];
const char *verstr = NULL;
struct connectdata *conn = userp;
- struct ssl_connect_data *connssl = &conn->ssl[0];
- struct ssl_backend_data *backend = connssl->backend;
+ int cf_idx = ossl_get_ssl_cf_index();
+ struct ssl_connect_data *connssl;
struct Curl_easy *data = NULL;
+ struct Curl_cfilter *cf;
- DEBUGASSERT(backend);
- data = backend->logger;
+ DEBUGASSERT(cf_idx >= 0);
+ cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx);
+ DEBUGASSERT(cf);
+ connssl = cf->ctx;
+ DEBUGASSERT(connssl);
+ DEBUGASSERT(connssl->backend);
+ data = connssl->backend->logger;
if(!conn || !data || !data->set.fdebug ||
(direction != 0 && direction != 1))
return;
- switch(ssl_ver) {
+ switch(ssl_ver) {
#ifdef SSL2_VERSION /* removed in recent versions */
case SSL2_VERSION:
verstr = "SSLv2";
@@ -2565,7 +2764,8 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
msg_name = ssl_msg_type(ssl_ver, msg_type);
}
- txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
+ txt_len = msnprintf(ssl_buf, sizeof(ssl_buf),
+ CFMSG(cf, "%s (%s), %s, %s (%d):\n"),
verstr, direction?"OUT":"IN",
tls_rt_name, msg_name, msg_type);
if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
@@ -2605,10 +2805,11 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
#ifdef HAS_MODERN_SET_PROTO_VER
static CURLcode
-set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
+set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
/* first, TLS min version... */
- long curl_ssl_version_min = SSL_CONN_CONFIG(version);
+ long curl_ssl_version_min = conn_config->version;
long curl_ssl_version_max;
/* convert curl min SSL version option to OpenSSL constant */
@@ -2652,7 +2853,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
}
/* ... then, TLS max version */
- curl_ssl_version_max = SSL_CONN_CONFIG(version_max);
+ curl_ssl_version_max = conn_config->version_max;
/* convert curl max SSL version option to OpenSSL constant */
switch(curl_ssl_version_max) {
@@ -2700,11 +2901,12 @@ typedef long ctx_option_t;
#if !defined(HAS_MODERN_SET_PROTO_VER)
static CURLcode
set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
- struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
(void) data; /* In case it's unused. */
@@ -2712,14 +2914,12 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ struct ssl_connect_data *connssl = cf->ctx;
+ DEBUGASSERT(connssl->backend);
+ SSL_CTX_set_max_proto_version(connssl->backend->ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
- (void)sockindex;
(void)ctx_options;
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
@@ -2780,31 +2980,30 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
int res = 0;
- struct connectdata *conn;
struct Curl_easy *data;
- int sockindex;
+ struct Curl_cfilter *cf;
+ const struct ssl_config_data *config;
curl_socket_t *sockindex_ptr;
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
bool isproxy;
- if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
+ if(data_idx < 0 || cf_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
return 0;
- conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx);
+ cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx);
data = (struct Curl_easy *) SSL_get_ex_data(ssl, data_idx);
/* The sockindex has been stored as a pointer to an array element */
sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
- if(!conn || !data || !sockindex_ptr)
+ if(!cf || !data || !sockindex_ptr)
return 0;
- sockindex = (int)(sockindex_ptr - conn->sock);
+ isproxy = Curl_ssl_cf_is_proxy(cf);
- isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE;
-
- if(SSL_SET_OPTION(primary.sessionid)) {
+ config = Curl_ssl_cf_get_config(cf, data);
+ if(config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *old_ssl_sessionid = NULL;
@@ -2813,8 +3012,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(isproxy)
incache = FALSE;
else
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
- &old_ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing");
@@ -2824,8 +3022,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
}
if(!incache) {
- if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- 0 /* unknown size */, sockindex, &added)) {
+ if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ 0 /* unknown size */, &added)) {
if(added) {
/* the session has been put into the session cache */
res = 1;
@@ -2840,7 +3038,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
return res;
}
-static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
+static CURLcode load_cacert_from_memory(X509_STORE *store,
const struct curl_blob *ca_info_blob)
{
/* these need to be freed at the end */
@@ -2849,16 +3047,11 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
/* everything else is just a reference */
int i, count = 0;
- X509_STORE *cts = NULL;
X509_INFO *itmp = NULL;
if(ca_info_blob->len > (size_t)INT_MAX)
return CURLE_SSL_CACERT_BADFILE;
- cts = SSL_CTX_get_cert_store(ctx);
- if(!cts)
- return CURLE_OUT_OF_MEMORY;
-
cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len);
if(!cbio)
return CURLE_OUT_OF_MEMORY;
@@ -2873,7 +3066,7 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
itmp = sk_X509_INFO_value(inf, i);
if(itmp->x509) {
- if(X509_STORE_add_cert(cts, itmp->x509)) {
+ if(X509_STORE_add_cert(store, itmp->x509)) {
++count;
}
else {
@@ -2883,7 +3076,7 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
}
}
if(itmp->crl) {
- if(X509_STORE_add_crl(cts, itmp->crl)) {
+ if(X509_STORE_add_crl(store, itmp->crl)) {
++count;
}
else {
@@ -2901,21 +3094,414 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE);
}
-static CURLcode ossl_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode populate_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ X509_STORE *store)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = CURLE_OK;
+ X509_LOOKUP *lookup = NULL;
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char * const ssl_capath = conn_config->CApath;
+ const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+ const bool verifypeer = conn_config->verifypeer;
+ bool imported_native_ca = false;
+
+ if(!store)
+ return CURLE_OUT_OF_MEMORY;
+
+#if defined(USE_WIN32_CRYPTO)
+ /* Import certificates from the Windows root certificate store if requested.
+ https://stackoverflow.com/questions/9507184/
+ https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
+ https://datatracker.ietf.org/doc/html/rfc5280 */
+ if((conn_config->verifypeer || conn_config->verifyhost) &&
+ (ssl_config->native_ca_store)) {
+ HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
+
+ if(hStore) {
+ PCCERT_CONTEXT pContext = NULL;
+ /* The array of enhanced key usage OIDs will vary per certificate and is
+ declared outside of the loop so that rather than malloc/free each
+ iteration we can grow it with realloc, when necessary. */
+ CERT_ENHKEY_USAGE *enhkey_usage = NULL;
+ DWORD enhkey_usage_size = 0;
+
+ /* This loop makes a best effort to import all valid certificates from
+ the MS root store. If a certificate cannot be imported it is skipped.
+ 'result' is used to store only hard-fail conditions (such as out of
+ memory) that cause an early break. */
+ result = CURLE_OK;
+ for(;;) {
+ X509 *x509;
+ FILETIME now;
+ BYTE key_usage[2];
+ DWORD req_size;
+ const unsigned char *encoded_cert;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ char cert_name[256];
+#endif
+
+ pContext = CertEnumCertificatesInStore(hStore, pContext);
+ if(!pContext)
+ break;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ NULL, cert_name, sizeof(cert_name))) {
+ strcpy(cert_name, "Unknown");
+ }
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
+#endif
+
+ encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
+ if(!encoded_cert)
+ continue;
+
+ GetSystemTimeAsFileTime(&now);
+ if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
+ CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
+ continue;
+
+ /* If key usage exists check for signing attribute */
+ if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
+ pContext->pCertInfo,
+ key_usage, sizeof(key_usage))) {
+ if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ continue;
+ }
+ else if(GetLastError())
+ continue;
+
+ /* If enhanced key usage exists check for server auth attribute.
+ *
+ * Note "In a Microsoft environment, a certificate might also have EKU
+ * extended properties that specify valid uses for the certificate."
+ * The call below checks both, and behavior varies depending on what is
+ * found. For more details see CertGetEnhancedKeyUsage doc.
+ */
+ if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
+ if(req_size && req_size > enhkey_usage_size) {
+ void *tmp = realloc(enhkey_usage, req_size);
+
+ if(!tmp) {
+ failf(data, "SSL: Out of memory allocating for OID list");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
+ enhkey_usage_size = req_size;
+ }
+
+ if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
+ if(!enhkey_usage->cUsageIdentifier) {
+ /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
+ good for all uses. If it returns zero, the certificate has no
+ valid uses." */
+ if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
+ continue;
+ }
+ else {
+ DWORD i;
+ bool found = false;
+
+ for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
+ if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
+ enhkey_usage->rgpszUsageIdentifier[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ if(!x509)
+ continue;
+
+ /* Try to import the certificate. This may fail for legitimate reasons
+ such as duplicate certificate, which is allowed by MS but not
+ OpenSSL. */
+ if(X509_STORE_add_cert(store, x509) == 1) {
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ infof(data, "SSL: Imported cert \"%s\"", cert_name);
+#endif
+ imported_native_ca = true;
+ }
+ X509_free(x509);
+ }
+
+ free(enhkey_usage);
+ CertFreeCertificateContext(pContext);
+ CertCloseStore(hStore, 0);
+
+ if(result)
+ return result;
+ }
+ if(imported_native_ca)
+ infof(data, "successfully imported Windows CA store");
+ else
+ infof(data, "error importing Windows CA store, continuing anyway");
+ }
+#endif
+
+ if(ca_info_blob) {
+ result = load_cacert_from_memory(store, ca_info_blob);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY ||
+ (verifypeer && !imported_native_ca)) {
+ failf(data, "error importing CA certificate blob");
+ return result;
+ }
+ /* Only warn if no certificate verification is required. */
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ }
+
+ if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
+#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
+ /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
+ if(ssl_cafile &&
+ !X509_STORE_load_file(store, ssl_cafile)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate file: %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ if(ssl_capath &&
+ !X509_STORE_load_path(store, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate path: %s", ssl_capath);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+#else
+ /* tell OpenSSL where to find CA certificates that are used to verify the
+ server's certificate. */
+ if(!X509_STORE_load_locations(store, ssl_cafile, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+#endif
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+
+#ifdef CURL_CA_FALLBACK
+ if(verifypeer &&
+ !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
+ /* verifying the peer without any CA certificates won't
+ work so use openssl's built-in default as fallback */
+ X509_STORE_set_default_paths(store);
+ }
+#endif
+
+ if(ssl_crlfile) {
+ /* tell OpenSSL where to find CRL file that is used to check certificate
+ * revocation */
+ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+ if(!lookup ||
+ (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
+ failf(data, "error loading CRL file: %s", ssl_crlfile);
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ /* Everything is fine. */
+ infof(data, "successfully loaded CRL file:");
+ X509_STORE_set_flags(store,
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+ infof(data, " CRLfile: %s", ssl_crlfile);
+ }
+
+ if(verifypeer) {
+ /* Try building a chain using issuers in the trusted store first to avoid
+ problems with server-sent legacy intermediates. Newer versions of
+ OpenSSL do alternate chain checking by default but we do not know how to
+ determine that in a reliable manner.
+ https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
+ */
+#if defined(X509_V_FLAG_TRUSTED_FIRST)
+ X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
+#endif
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+ if(!ssl_config->no_partialchain && !ssl_crlfile) {
+ /* Have intermediate certificates in the trust store be treated as
+ trust-anchors, in the same way as self-signed root CA certificates
+ are. This allows users to verify servers using the intermediate cert
+ only, instead of needing the whole chain.
+
+ Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
+ cannot do partial chains with a CRL check.
+ */
+ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
+ }
+#endif
+ }
+
+ return result;
+}
+
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+static bool cached_x509_store_expired(const struct Curl_easy *data,
+ const struct multi_ssl_backend_data *mb)
+{
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+
+ if(timeout_ms < 0)
+ return false;
+
+ return elapsed_ms >= timeout_ms;
+}
+
+static bool cached_x509_store_different(
+ struct Curl_cfilter *cf,
+ const struct multi_ssl_backend_data *mb)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!mb->CAfile || !conn_config->CAfile)
+ return mb->CAfile != conn_config->CAfile;
+
+ return strcmp(mb->CAfile, conn_config->CAfile);
+}
+
+static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ X509_STORE *store = NULL;
+
+ if(multi &&
+ multi->ssl_backend_data &&
+ multi->ssl_backend_data->store &&
+ !cached_x509_store_expired(data, multi->ssl_backend_data) &&
+ !cached_x509_store_different(cf, multi->ssl_backend_data)) {
+ store = multi->ssl_backend_data->store;
+ }
+
+ return store;
+}
+
+static void set_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ X509_STORE *store)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct multi_ssl_backend_data *mbackend;
+
+ if(!multi)
+ return;
+
+ if(!multi->ssl_backend_data) {
+ multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));
+ if(!multi->ssl_backend_data)
+ return;
+ }
+
+ mbackend = multi->ssl_backend_data;
+
+ if(X509_STORE_up_ref(store)) {
+ char *CAfile = NULL;
+
+ if(conn_config->CAfile) {
+ CAfile = strdup(conn_config->CAfile);
+ if(!CAfile) {
+ X509_STORE_free(store);
+ return;
+ }
+ }
+
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ free(mbackend->CAfile);
+ }
+
+ mbackend->time = Curl_now();
+ mbackend->store = store;
+ mbackend->CAfile = CAfile;
+ }
+}
+
+static CURLcode set_up_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_backend_data *backend)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = CURLE_OK;
+ X509_STORE *cached_store;
+ bool cache_criteria_met;
+
+ /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
+ or no source is provided and we are falling back to openssl's built-in
+ default. */
+ cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
+ conn_config->verifypeer &&
+ !conn_config->CApath &&
+ !conn_config->ca_info_blob &&
+ !ssl_config->primary.CRLfile &&
+ !ssl_config->native_ca_store;
+
+ cached_store = get_cached_x509_store(cf, data);
+ if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
+ SSL_CTX_set_cert_store(backend->ctx, cached_store);
+ }
+ else {
+ X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
+
+ result = populate_x509_store(cf, data, store);
+ if(result == CURLE_OK && cache_criteria_met) {
+ set_cached_x509_store(cf, data, store);
+ }
+ }
+
+ return result;
+}
+#else /* HAVE_SSL_X509_STORE_SHARE */
+static CURLcode set_up_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_backend_data *backend)
+{
+ X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
+
+ return populate_x509_store(cf, data, store);
+}
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- X509_LOOKUP *lookup = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
void *ssl_sessionid = NULL;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ BIO *bio;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
- const char * const hostname = SSL_HOST_NAME();
+ const char *hostname = connssl->hostname;
#ifdef ENABLE_IPV6
struct in6_addr addr;
@@ -2923,23 +3509,16 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
struct in_addr addr;
#endif
#endif
- const long int ssl_version = SSL_CONN_CONFIG(version);
+ const long int ssl_version = conn_config->version;
#ifdef USE_OPENSSL_SRP
- const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype);
+ const enum CURL_TLSAUTH ssl_authtype = ssl_config->primary.authtype;
#endif
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
- const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
- const char * const ssl_cafile =
- /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile);
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ const char * const ssl_cert_type = ssl_config->cert_type;
+ const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
struct ssl_backend_data *backend = connssl->backend;
- bool imported_native_ca = false;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
DEBUGASSERT(backend);
@@ -2949,7 +3528,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(result)
return result;
- SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK;
+ ssl_config->certverifyresult = !X509_V_OK;
/* check to see if we've been told to use an explicit SSL/TLS version */
@@ -2979,7 +3558,12 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- DEBUGASSERT(!backend->ctx);
+ if(backend->ctx) {
+ /* This happens when an error was encountered before in this
+ * step and we are called to do it again. Get rid of any leftover
+ * from the previous call. */
+ ossl_close(cf, data);
+ }
backend->ctx = SSL_CTX_new(req_method);
if(!backend->ctx) {
@@ -2996,8 +3580,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
- SSL_CTX_set_msg_callback_arg(backend->ctx, conn);
- set_logger(conn, data);
+ SSL_CTX_set_msg_callback_arg(backend->ctx, cf->conn);
+ set_logger(connssl, data);
}
#endif
@@ -3055,7 +3639,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
/* unless the user explicitly asks to allow the protocol vulnerability we
use the work-around */
- if(!SSL_SET_OPTION(enable_beast))
+ if(!ssl_config->enable_beast)
ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
@@ -3077,10 +3661,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
ctx_options |= SSL_OP_NO_SSLv3;
#if HAS_MODERN_SET_PROTO_VER /* 1.1.0 */
- result = set_ssl_version_min_max(backend->ctx, conn);
+ result = set_ssl_version_min_max(cf, backend->ctx);
#else
- result = set_ssl_version_min_max_legacy(&ctx_options, data, conn,
- sockindex);
+ result = set_ssl_version_min_max_legacy(&ctx_options, cf, data);
#endif
if(result != CURLE_OK)
return result;
@@ -3094,14 +3677,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
SSL_CTX_set_options(backend->ctx, ctx_options);
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
protocols[cur++] = ALPN_H2_LENGTH;
@@ -3131,15 +3714,15 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(!result &&
!cert_stuff(data, backend->ctx,
ssl_cert, ssl_cert_blob, ssl_cert_type,
- SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
- SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd)))
+ ssl_config->key, ssl_config->key_blob,
+ ssl_config->key_type, ssl_config->key_passwd))
result = CURLE_SSL_CERTPROBLEM;
if(result)
/* failf() is already done in cert_stuff() */
return result;
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(!ciphers)
ciphers = (char *)DEFAULT_CIPHER_SELECTION;
if(ciphers) {
@@ -3152,7 +3735,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
- char *ciphers13 = SSL_CONN_CONFIG(cipher_list13);
+ char *ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
@@ -3170,7 +3753,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
- char *curves = SSL_CONN_CONFIG(curves);
+ char *curves = conn_config->curves;
if(curves) {
if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
@@ -3183,8 +3766,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef USE_OPENSSL_SRP
if((ssl_authtype == CURL_TLSAUTH_SRP) &&
Curl_auth_allowed_to_host(data)) {
- char * const ssl_username = SSL_SET_OPTION(primary.username);
- char * const ssl_password = SSL_SET_OPTION(primary.password);
+ char * const ssl_username = ssl_config->primary.username;
+ char * const ssl_password = ssl_config->primary.password;
infof(data, "Using TLS-SRP username: %s", ssl_username);
if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
@@ -3195,7 +3778,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CONN_CONFIG(cipher_list)) {
+ if(!conn_config->cipher_list) {
infof(data, "Setting cipher list SRP");
if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
@@ -3206,249 +3789,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
#endif
-
-#if defined(USE_WIN32_CRYPTO)
- /* Import certificates from the Windows root certificate store if requested.
- https://stackoverflow.com/questions/9507184/
- https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
- https://datatracker.ietf.org/doc/html/rfc5280 */
- if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
- (SSL_SET_OPTION(native_ca_store))) {
- X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
- HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
-
- if(hStore) {
- PCCERT_CONTEXT pContext = NULL;
- /* The array of enhanced key usage OIDs will vary per certificate and is
- declared outside of the loop so that rather than malloc/free each
- iteration we can grow it with realloc, when necessary. */
- CERT_ENHKEY_USAGE *enhkey_usage = NULL;
- DWORD enhkey_usage_size = 0;
-
- /* This loop makes a best effort to import all valid certificates from
- the MS root store. If a certificate cannot be imported it is skipped.
- 'result' is used to store only hard-fail conditions (such as out of
- memory) that cause an early break. */
- result = CURLE_OK;
- for(;;) {
- X509 *x509;
- FILETIME now;
- BYTE key_usage[2];
- DWORD req_size;
- const unsigned char *encoded_cert;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- char cert_name[256];
-#endif
-
- pContext = CertEnumCertificatesInStore(hStore, pContext);
- if(!pContext)
- break;
-
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
- NULL, cert_name, sizeof(cert_name))) {
- strcpy(cert_name, "Unknown");
- }
- infof(data, "SSL: Checking cert \"%s\"", cert_name);
-#endif
-
- encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
- if(!encoded_cert)
- continue;
-
- GetSystemTimeAsFileTime(&now);
- if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
- CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
- continue;
-
- /* If key usage exists check for signing attribute */
- if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
- pContext->pCertInfo,
- key_usage, sizeof(key_usage))) {
- if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
- continue;
- }
- else if(GetLastError())
- continue;
-
- /* If enhanced key usage exists check for server auth attribute.
- *
- * Note "In a Microsoft environment, a certificate might also have EKU
- * extended properties that specify valid uses for the certificate."
- * The call below checks both, and behavior varies depending on what is
- * found. For more details see CertGetEnhancedKeyUsage doc.
- */
- if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
- if(req_size && req_size > enhkey_usage_size) {
- void *tmp = realloc(enhkey_usage, req_size);
-
- if(!tmp) {
- failf(data, "SSL: Out of memory allocating for OID list");
- result = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
- enhkey_usage_size = req_size;
- }
-
- if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
- if(!enhkey_usage->cUsageIdentifier) {
- /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
- good for all uses. If it returns zero, the certificate has no
- valid uses." */
- if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
- continue;
- }
- else {
- DWORD i;
- bool found = false;
-
- for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
- if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
- enhkey_usage->rgpszUsageIdentifier[i])) {
- found = true;
- break;
- }
- }
-
- if(!found)
- continue;
- }
- }
- else
- continue;
- }
- else
- continue;
-
- x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
- if(!x509)
- continue;
-
- /* Try to import the certificate. This may fail for legitimate reasons
- such as duplicate certificate, which is allowed by MS but not
- OpenSSL. */
- if(X509_STORE_add_cert(store, x509) == 1) {
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- infof(data, "SSL: Imported cert \"%s\"", cert_name);
-#endif
- imported_native_ca = true;
- }
- X509_free(x509);
- }
-
- free(enhkey_usage);
- CertFreeCertificateContext(pContext);
- CertCloseStore(hStore, 0);
-
- if(result)
- return result;
- }
- if(imported_native_ca)
- infof(data, "successfully imported Windows CA store");
- else
- infof(data, "error importing Windows CA store, continuing anyway");
- }
-#endif
-
- if(ca_info_blob) {
- result = load_cacert_from_memory(backend->ctx, ca_info_blob);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY ||
- (verifypeer && !imported_native_ca)) {
- failf(data, "error importing CA certificate blob");
- return result;
- }
- /* Only warn if no certificate verification is required. */
- infof(data, "error importing CA certificate blob, continuing anyway");
- }
- }
-
- if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
-#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
- /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
- if(ssl_cafile &&
- !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate file: %s", ssl_cafile);
- return CURLE_SSL_CACERT_BADFILE;
- }
- if(ssl_capath &&
- !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate path: %s", ssl_capath);
- return CURLE_SSL_CACERT_BADFILE;
- }
-#else
- /* tell OpenSSL where to find CA certificates that are used to verify the
- server's certificate. */
- if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:"
- " CAfile: %s CApath: %s",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
-#endif
- infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
- }
-
-#ifdef CURL_CA_FALLBACK
- if(verifypeer &&
- !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
- /* verifying the peer without any CA certificates won't
- work so use openssl's built-in default as fallback */
- SSL_CTX_set_default_verify_paths(backend->ctx);
- }
-#endif
-
- if(ssl_crlfile) {
- /* tell OpenSSL where to find CRL file that is used to check certificate
- * revocation */
- lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx),
- X509_LOOKUP_file());
- if(!lookup ||
- (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
- failf(data, "error loading CRL file: %s", ssl_crlfile);
- return CURLE_SSL_CRL_BADFILE;
- }
- /* Everything is fine. */
- infof(data, "successfully loaded CRL file:");
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
-
- infof(data, " CRLfile: %s", ssl_crlfile);
- }
-
- if(verifypeer) {
- /* Try building a chain using issuers in the trusted store first to avoid
- problems with server-sent legacy intermediates. Newer versions of
- OpenSSL do alternate chain checking by default but we do not know how to
- determine that in a reliable manner.
- https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
- */
-#if defined(X509_V_FLAG_TRUSTED_FIRST)
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_TRUSTED_FIRST);
-#endif
-#ifdef X509_V_FLAG_PARTIAL_CHAIN
- if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) {
- /* Have intermediate certificates in the trust store be treated as
- trust-anchors, in the same way as self-signed root CA certificates
- are. This allows users to verify servers using the intermediate cert
- only, instead of needing the whole chain.
-
- Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
- cannot do partial chains with a CRL check.
- */
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_PARTIAL_CHAIN);
- }
-#endif
- }
+ result = set_up_x509_store(cf, data, backend);
+ if(result)
+ return result;
/* OpenSSL always tries to verify the peer, this only says whether it should
* fail to connect if the verification fails, or if it should continue
@@ -3495,7 +3838,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(SSL_CONN_CONFIG(verifystatus))
+ if(conn_config->verifystatus)
SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
@@ -3520,18 +3863,17 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
#endif
- if(!ossl_associate_connection(data, conn, sockindex)) {
+ if(!ossl_attach_data(cf, data)) {
/* Maybe the internal errors of SSL_get_ex_new_index or SSL_set_ex_data */
- failf(data, "SSL: ossl_associate_connection failed: %s",
+ failf(data, "SSL: ossl_attach_data failed: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
@@ -3546,40 +3888,25 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
Curl_ssl_sessionid_unlock(data);
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- BIO *const bio = BIO_new(BIO_f_ssl());
- struct ssl_backend_data *proxy_backend;
- SSL* handle = NULL;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(proxy_backend);
- handle = proxy_backend->handle;
- DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(handle != NULL);
- DEBUGASSERT(bio != NULL);
- BIO_set_ssl(bio, handle, FALSE);
- SSL_set_bio(backend->handle, bio, bio);
- }
- else
-#endif
- if(!SSL_set_fd(backend->handle, (int)sockfd)) {
- /* pass the raw socket into the SSL layers */
- failf(data, "SSL: SSL_set_fd failed: %s",
- ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
+ bio = BIO_new(bio_cf_method);
+ if(!bio)
+ return CURLE_OUT_OF_MEMORY;
+
+ BIO_set_data(bio, cf);
+ SSL_set_bio(backend->handle, bio, bio);
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
-static CURLcode ossl_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
int err;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
@@ -3617,6 +3944,9 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
return CURLE_OK;
}
#endif
+ else if(backend->io_result == CURLE_AGAIN) {
+ return CURLE_OK;
+ }
else {
/* untreated error */
unsigned long errdetail;
@@ -3644,7 +3974,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
lerr = SSL_get_verify_result(backend->handle);
if(lerr != X509_V_OK) {
- SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
+ ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
"SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
@@ -3679,15 +4009,14 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
* the SO_ERROR is also lost.
*/
if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
char extramsg[80]="";
int sockerr = SOCKERRNO;
+
if(sockerr && detail == SSL_ERROR_SYSCALL)
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
- failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ",
+ failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- hostname, port);
+ connssl->hostname, connssl->port);
return result;
}
@@ -3710,7 +4039,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
*/
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const unsigned char *neg_protocol;
unsigned int len;
SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
@@ -3720,19 +4049,19 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
#ifdef USE_HTTP2
if(len == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, neg_protocol, len)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -3807,11 +4136,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
* We check certificates to authenticate the server; otherwise we risk
* man-in-the-middle attack.
*/
-static CURLcode servercert(struct Curl_easy *data,
- struct connectdata *conn,
- struct ssl_connect_data *connssl,
+static CURLcode servercert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool strict)
{
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result = CURLE_OK;
int rc;
long lerr;
@@ -3848,7 +4180,8 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
- infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server");
+ infof(data, "%s certificate:",
+ Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
buffer, sizeof(buffer));
@@ -3871,7 +4204,7 @@ static CURLcode servercert(struct Curl_easy *data,
BIO_free(mem);
- if(SSL_CONN_CONFIG(verifyhost)) {
+ if(conn_config->verifyhost) {
result = Curl_ossl_verifyhost(data, conn, backend->server_cert);
if(result) {
X509_free(backend->server_cert);
@@ -3894,10 +4227,10 @@ static CURLcode servercert(struct Curl_easy *data,
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) {
- if(SSL_CONN_CONFIG(issuercert_blob)) {
- fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data,
- (int)SSL_CONN_CONFIG(issuercert_blob)->len);
+ if(conn_config->issuercert || conn_config->issuercert_blob) {
+ if(conn_config->issuercert_blob) {
+ fp = BIO_new_mem_buf(conn_config->issuercert_blob->data,
+ (int)conn_config->issuercert_blob->len);
if(!fp) {
failf(data,
"BIO_new_mem_buf NULL, " OSSL_PACKAGE
@@ -3922,10 +4255,10 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) {
+ if(BIO_read_filename(fp, conn_config->issuercert) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3937,7 +4270,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3948,7 +4281,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3957,15 +4290,15 @@ static CURLcode servercert(struct Curl_easy *data,
}
infof(data, " SSL certificate issuer check ok (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
}
lerr = SSL_get_verify_result(backend->handle);
- SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
+ ssl_config->certverifyresult = lerr;
if(lerr != X509_V_OK) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(conn_config->verifypeer) {
/* We probably never reach this, because SSL_connect() will fail
and we return earlier if verifypeer is set? */
if(strict)
@@ -3984,8 +4317,8 @@ static CURLcode servercert(struct Curl_easy *data,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(SSL_CONN_CONFIG(verifystatus)) {
- result = verifystatus(data, connssl);
+ if(conn_config->verifystatus) {
+ result = verifystatus(cf, data);
if(result) {
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3998,7 +4331,9 @@ static CURLcode servercert(struct Curl_easy *data,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
- ptr = SSL_PINNED_PUB_KEY();
+ ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(!result && ptr) {
result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
if(result)
@@ -4012,11 +4347,12 @@ static CURLcode servercert(struct Curl_easy *data,
return result;
}
-static CURLcode ossl_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -4027,8 +4363,8 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data,
* operations.
*/
- result = servercert(data, conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
- SSL_CONN_CONFIG(verifyhost)));
+ result = servercert(cf, data, conn_config->verifypeer ||
+ conn_config->verifyhost);
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -4036,18 +4372,14 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data,
return result;
}
-static Curl_recv ossl_recv;
-static Curl_send ossl_send;
-
-static CURLcode ossl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
- CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ CURLcode result = CURLE_OK;
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -4066,9 +4398,9 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = ossl_connect_step1(data, conn, sockindex);
+ result = ossl_connect_step1(cf, data);
if(result)
- return result;
+ goto out;
}
while(ssl_connect_2 == connssl->connecting_state ||
@@ -4081,7 +4413,8 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
if(timeout_ms < 0) {
/* no need to continue if time already is up */
failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
/* if ssl is expecting something, check if it's available. */
@@ -4098,16 +4431,19 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(0 == what) {
if(nonblocking) {
*done = FALSE;
- return CURLE_OK;
+ result = CURLE_OK;
+ goto out;
}
/* timeout */
failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
/* socket is readable or writable */
}
@@ -4118,25 +4454,23 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- result = ossl_connect_step2(data, conn, sockindex);
+ result = ossl_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state)))
- return result;
+ goto out;
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = ossl_connect_step3(data, conn, sockindex);
+ result = ossl_connect_step3(cf, data);
if(result)
- return result;
+ goto out;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = ossl_recv;
- conn->send[sockindex] = ossl_send;
*done = TRUE;
}
else
@@ -4145,24 +4479,24 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
/* Reset our connect state machine */
connssl->connecting_state = ssl_connect_1;
- return CURLE_OK;
+out:
+ return result;
}
-static CURLcode ossl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool *done)
{
- return ossl_connect_common(data, conn, sockindex, TRUE, done);
+ return ossl_connect_common(cf, data, TRUE, done);
}
-static CURLcode ossl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode ossl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = ossl_connect_common(data, conn, sockindex, FALSE, &done);
+ result = ossl_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -4171,28 +4505,20 @@ static CURLcode ossl_connect(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static bool ossl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool ossl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- DEBUGASSERT(connssl->backend);
- if(connssl->backend->handle && SSL_pending(connssl->backend->handle))
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->handle && SSL_pending(ctx->backend->handle))
return TRUE;
-#ifndef CURL_DISABLE_PROXY
- {
- const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
- DEBUGASSERT(proxyssl->backend);
- if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle))
- return TRUE;
- }
-#endif
return FALSE;
}
-static size_t ossl_version(char *buffer, size_t size);
-
-static ssize_t ossl_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t ossl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
@@ -4204,16 +4530,16 @@ static ssize_t ossl_send(struct Curl_easy *data,
unsigned long sslerror;
int memlen;
int rc;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- set_logger(conn, data);
+ set_logger(connssl, data);
rc = SSL_write(backend->handle, mem, memlen);
if(rc <= 0) {
@@ -4226,10 +4552,17 @@ static ssize_t ossl_send(struct Curl_easy *data,
should be called again later. This is basically an EWOULDBLOCK
equivalent. */
*curlcode = CURLE_AGAIN;
- return -1;
+ rc = -1;
+ goto out;
case SSL_ERROR_SYSCALL:
{
int sockerr = SOCKERRNO;
+
+ if(backend->io_result == CURLE_AGAIN) {
+ *curlcode = CURLE_AGAIN;
+ rc = -1;
+ goto out;
+ }
sslerror = ERR_get_error();
if(sslerror)
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
@@ -4242,18 +4575,20 @@ static ssize_t ossl_send(struct Curl_easy *data,
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_SEND_ERROR;
- return -1;
+ rc = -1;
+ goto out;
}
- case SSL_ERROR_SSL:
+ case SSL_ERROR_SSL: {
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
sslerror = ERR_get_error();
if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
- conn->ssl[sockindex].state == ssl_connection_complete
-#ifndef CURL_DISABLE_PROXY
- && conn->proxy_ssl[sockindex].state == ssl_connection_complete
-#endif
+ connssl->state == ssl_connection_complete &&
+ (connssl_next && connssl_next->state == ssl_connection_complete)
) {
char ver[120];
(void)ossl_version(ver, sizeof(ver));
@@ -4263,20 +4598,26 @@ static ssize_t ossl_send(struct Curl_easy *data,
failf(data, "SSL_write() error: %s",
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
*curlcode = CURLE_SEND_ERROR;
- return -1;
+ rc = -1;
+ goto out;
+ }
+ default:
+ /* a true error */
+ failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ rc = -1;
+ goto out;
}
- /* a true error */
- failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
- SSL_ERROR_to_str(err), SOCKERRNO);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
}
*curlcode = CURLE_OK;
+
+out:
return (ssize_t)rc; /* number of bytes */
}
-static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
- int num, /* socketindex */
+static ssize_t ossl_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
@@ -4285,17 +4626,19 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
unsigned long sslerror;
ssize_t nread;
int buffsize;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- set_logger(conn, data);
+ set_logger(connssl, data);
nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
+
if(nread <= 0) {
/* failed SSL_read */
int err = SSL_get_error(backend->handle, (int)nread);
@@ -4305,7 +4648,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
break;
case SSL_ERROR_ZERO_RETURN: /* no more data */
/* close_notify alert */
- if(num == FIRSTSOCKET)
+ if(cf->sockindex == FIRSTSOCKET)
/* mark the connection for close if it is indeed the control
connection */
connclose(conn, "TLS close_notify");
@@ -4314,11 +4657,17 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
- return -1;
+ nread = -1;
+ goto out;
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
/* https://www.openssl.org/docs/crypto/ERR_get_error.html */
+ if(backend->io_result == CURLE_AGAIN) {
+ *curlcode = CURLE_AGAIN;
+ nread = -1;
+ goto out;
+ }
sslerror = ERR_get_error();
if((nread < 0) || sslerror) {
/* If the return code was negative or there actually is an error in the
@@ -4335,7 +4684,8 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ nread = -1;
+ goto out;
}
/* For debug builds be a little stricter and error on any
SSL_ERROR_SYSCALL. For example a server may have closed the connection
@@ -4358,11 +4708,14 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
" (Fatal because this is a curl debug build)",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ nread = -1;
+ goto out;
}
#endif
}
}
+
+out:
return nread;
}
@@ -4374,7 +4727,7 @@ static size_t ossl_version(char *buffer, size_t size)
int count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
- if(Curl_strncasecompare(ver, expected, sizeof(expected) - 1)) {
+ if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
ver += sizeof(expected) - 1;
}
count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
@@ -4501,41 +4854,44 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
(void *)backend->ctx : (void *)backend->handle;
}
-static bool ossl_associate_connection(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static bool ossl_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ const struct ssl_config_data *config;
+
DEBUGASSERT(backend);
/* If we don't have SSL context, do nothing. */
if(!backend->handle)
return FALSE;
- if(SSL_SET_OPTION(primary.sessionid)) {
+ config = Curl_ssl_cf_get_config(cf, data);
+ if(config->primary.sessionid) {
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
- if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 &&
proxy_idx >= 0) {
- int data_status, conn_status, sockindex_status, proxy_status;
+ int data_status, cf_status, sockindex_status, proxy_status;
/* Store the data needed for the "new session" callback.
* The sockindex is stored as a pointer to an array element. */
data_status = SSL_set_ex_data(backend->handle, data_idx, data);
- conn_status = SSL_set_ex_data(backend->handle, connectdata_idx, conn);
+ cf_status = SSL_set_ex_data(backend->handle, cf_idx, cf);
sockindex_status = SSL_set_ex_data(backend->handle, sockindex_idx,
- conn->sock + sockindex);
+ cf->conn->sock + cf->sockindex);
#ifndef CURL_DISABLE_PROXY
proxy_status = SSL_set_ex_data(backend->handle, proxy_idx,
- SSL_IS_PROXY() ? (void *) 1 : NULL);
+ Curl_ssl_cf_is_proxy(cf)?
+ (void *) 1 : NULL);
#else
proxy_status = SSL_set_ex_data(backend->handle, proxy_idx, NULL);
#endif
- if(data_status && conn_status && sockindex_status && proxy_status)
+ if(data_status && cf_status && sockindex_status && proxy_status)
return TRUE;
}
return FALSE;
@@ -4551,11 +4907,11 @@ static bool ossl_associate_connection(struct Curl_easy *data,
* transfer that might still be using the same connection.
*/
-static void ossl_disassociate_connection(struct Curl_easy *data,
- int sockindex)
+static void ossl_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
@@ -4563,24 +4919,38 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
if(!backend->handle)
return;
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
- if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 &&
proxy_idx >= 0) {
/* Disable references to data in "new session" callback to avoid
* accessing a stale pointer. */
SSL_set_ex_data(backend->handle, data_idx, NULL);
- SSL_set_ex_data(backend->handle, connectdata_idx, NULL);
+ SSL_set_ex_data(backend->handle, cf_idx, NULL);
SSL_set_ex_data(backend->handle, sockindex_idx, NULL);
SSL_set_ex_data(backend->handle, proxy_idx, NULL);
}
}
}
+static void ossl_free_multi_ssl_backend_data(
+ struct multi_ssl_backend_data *mbackend)
+{
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ }
+ free(mbackend->CAfile);
+ free(mbackend);
+#else /* HAVE_SSL_X509_STORE_SHARE */
+ (void)mbackend;
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+}
+
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
@@ -4606,7 +4976,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
ossl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks,/* getsock */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
@@ -4620,8 +4990,11 @@ const struct Curl_ssl Curl_ssl_openssl = {
#else
NULL, /* sha256sum */
#endif
- ossl_associate_connection, /* associate_connection */
- ossl_disassociate_connection /* disassociate_connection */
+ ossl_attach_data, /* use of data in this connection */
+ ossl_detach_data, /* remote of data from this connection */
+ ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
+ ossl_recv, /* recv decrypted data */
+ ossl_send, /* send data to encrypt */
};
#endif /* USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index 77a49f1..27f4ec8 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -35,6 +35,7 @@
#include "urldata.h"
#include "sendf.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "select.h"
#include "strerror.h"
#include "multiif.h"
@@ -63,43 +64,64 @@ static CURLcode map_error(rustls_result r)
}
static bool
-cr_data_pending(const struct connectdata *conn, int sockindex)
+cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return backend->data_pending;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return ctx->backend->data_pending;
}
static CURLcode
-cr_connect(struct Curl_easy *data UNUSED_PARAM,
- struct connectdata *conn UNUSED_PARAM,
- int sockindex UNUSED_PARAM)
+cr_connect(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
infof(data, "rustls_connect: unimplemented");
return CURLE_SSL_CONNECT_ERROR;
}
+struct io_ctx {
+ struct Curl_cfilter *cf;
+ struct Curl_easy *data;
+};
+
static int
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- ssize_t n = sread(*(int *)userdata, buf, len);
- if(n < 0) {
- return SOCKERRNO;
+ struct io_ctx *io_ctx = userdata;
+ CURLcode result;
+ int ret = 0;
+ ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
+ (char *)buf, len, &result);
+ if(nread < 0) {
+ nread = 0;
+ if(CURLE_AGAIN == result)
+ ret = EAGAIN;
+ else
+ ret = EINVAL;
}
- *out_n = n;
- return 0;
+ *out_n = (int)nread;
+ return ret;
}
static int
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- ssize_t n = swrite(*(int *)userdata, buf, len);
- if(n < 0) {
- return SOCKERRNO;
+ struct io_ctx *io_ctx = userdata;
+ CURLcode result;
+ int ret = 0;
+ ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
+ (const char *)buf, len, &result);
+ if(nwritten < 0) {
+ nwritten = 0;
+ if(CURLE_AGAIN == result)
+ ret = EAGAIN;
+ else
+ ret = EINVAL;
}
- *out_n = n;
- return 0;
+ *out_n = (int)nwritten;
+ return ret;
}
/*
@@ -115,13 +137,13 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
* output buffer.
*/
static ssize_t
-cr_recv(struct Curl_easy *data, int sockindex,
+cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *plainbuf, size_t plainlen, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ struct io_ctx io_ctx;
size_t n = 0;
size_t tls_bytes_read = 0;
@@ -133,10 +155,13 @@ cr_recv(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
rconn = backend->conn;
- io_error = rustls_connection_read_tls(rconn, read_cb,
- &conn->sock[sockindex], &tls_bytes_read);
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
+ io_error = rustls_connection_read_tls(rconn, read_cb, &io_ctx,
+ &tls_bytes_read);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- infof(data, "sread: EAGAIN or EWOULDBLOCK");
+ infof(data, CFMSG(cf, "cr_recv: EAGAIN or EWOULDBLOCK"));
}
else if(io_error) {
char buffer[STRERROR_LEN];
@@ -146,7 +171,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
return -1;
}
- infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
+ infof(data, CFMSG(cf, "cr_recv: read %ld TLS bytes"), tls_bytes_read);
rresult = rustls_connection_process_new_packets(rconn);
if(rresult != RUSTLS_RESULT_OK) {
@@ -164,7 +189,8 @@ cr_recv(struct Curl_easy *data, int sockindex,
plainlen - plain_bytes_copied,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
- infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later.");
+ infof(data, CFMSG(cf, "cr_recv: got PLAINTEXT_EMPTY. "
+ "will try again later."));
backend->data_pending = FALSE;
break;
}
@@ -181,7 +207,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
break;
}
else {
- infof(data, "cr_recv copied out %ld bytes of plaintext", n);
+ infof(data, CFMSG(cf, "cr_recv: got %ld plain bytes"), n);
plain_bytes_copied += n;
}
}
@@ -216,13 +242,13 @@ cr_recv(struct Curl_easy *data, int sockindex,
* It will only drain rustls' plaintext output buffer into the socket.
*/
static ssize_t
-cr_send(struct Curl_easy *data, int sockindex,
+cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *plainbuf, size_t plainlen, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ struct io_ctx io_ctx;
size_t plainwritten = 0;
size_t tlswritten = 0;
size_t tlswritten_total = 0;
@@ -232,7 +258,7 @@ cr_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
rconn = backend->conn;
- infof(data, "cr_send %ld bytes of plaintext", plainlen);
+ infof(data, CFMSG(cf, "cr_send: %ld plain bytes"), plainlen);
if(plainlen > 0) {
rresult = rustls_connection_write(rconn, plainbuf, plainlen,
@@ -249,11 +275,15 @@ cr_send(struct Curl_easy *data, int sockindex,
}
}
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
while(rustls_connection_wants_write(rconn)) {
- io_error = rustls_connection_write_tls(rconn, write_cb,
- &conn->sock[sockindex], &tlswritten);
+ io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+ &tlswritten);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total);
+ infof(data, CFMSG(cf, "cr_send: EAGAIN after %ld bytes"),
+ tlswritten_total);
*err = CURLE_AGAIN;
return -1;
}
@@ -269,7 +299,7 @@ cr_send(struct Curl_easy *data, int sockindex,
*err = CURLE_WRITE_ERROR;
return -1;
}
- infof(data, "cr_send wrote %ld bytes to network", tlswritten);
+ infof(data, CFMSG(cf, "cr_send: wrote %ld TLS bytes"), tlswritten);
tlswritten_total += tlswritten;
}
@@ -302,18 +332,20 @@ cr_hostname_is_ip(const char *hostname)
}
static CURLcode
-cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
+cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_backend_data *const backend)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct rustls_connection *rconn = NULL;
struct rustls_client_config_builder *config_builder = NULL;
struct rustls_root_cert_store *roots = NULL;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char *hostname = conn->host.name;
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ const char *hostname = connssl->hostname;
char errorbuf[256];
size_t errorlen;
int result;
@@ -400,7 +432,7 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
}
static void
-cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
+cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
const struct rustls_connection *rconn)
{
const uint8_t *protocol = NULL;
@@ -415,29 +447,29 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_H2);
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(len == ALPN_HTTP_1_1_LENGTH &&
0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_HTTP_1_1);
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
else {
infof(data, "ALPN, negotiated an unrecognized protocol");
}
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
static CURLcode
-cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, bool *done)
+cr_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool *done)
{
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
CURLcode tmperr = CURLE_OK;
@@ -451,7 +483,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
DEBUGASSERT(backend);
if(ssl_connection_none == connssl->state) {
- result = cr_init_backend(data, conn, connssl->backend);
+ result = cr_init_backend(cf, data, connssl->backend);
if(result != CURLE_OK) {
return result;
}
@@ -471,10 +503,8 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* Done with the handshake. Set up callbacks to send/receive data. */
connssl->state = ssl_connection_complete;
- cr_set_negotiated_alpn(data, conn, rconn);
+ cr_set_negotiated_alpn(cf, data, rconn);
- conn->recv[sockindex] = cr_recv;
- conn->send[sockindex] = cr_send;
*done = TRUE;
return CURLE_OK;
}
@@ -502,7 +532,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
if(wants_write) {
infof(data, "rustls_connection wants us to write_tls.");
- cr_send(data, sockindex, NULL, 0, &tmperr);
+ cr_send(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
infof(data, "writing would block");
/* fall through */
@@ -515,7 +545,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
if(wants_read) {
infof(data, "rustls_connection wants us to read_tls.");
- cr_recv(data, sockindex, NULL, 0, &tmperr);
+ cr_recv(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
infof(data, "reading would block");
/* fall through */
@@ -539,13 +569,15 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* returns a bitmap of flags for this connection's first socket indicating
whether we want to read or write */
static int
-cr_getsock(struct connectdata *conn, curl_socket_t *socks)
+cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks)
{
- struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ struct ssl_connect_data *const connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ (void)data;
DEBUGASSERT(backend);
rconn = backend->conn;
@@ -571,10 +603,9 @@ cr_get_internals(struct ssl_connect_data *connssl,
}
static void
-cr_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CURLcode tmperr = CURLE_OK;
ssize_t n = 0;
@@ -583,7 +614,7 @@ cr_close(struct Curl_easy *data, struct connectdata *conn,
if(backend->conn) {
rustls_connection_send_close_notify(backend->conn);
- n = cr_send(data, sockindex, NULL, 0, &tmperr);
+ n = cr_send(cf, data, NULL, 0, &tmperr);
if(n < 0) {
failf(data, "error sending close notify: %d", tmperr);
}
@@ -606,7 +637,8 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */
@@ -619,7 +651,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_cert_status_request, /* cert_status_request */
cr_connect, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- cr_getsock, /* cr_getsock */
+ cr_get_select_socks, /* get_select_socks */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -630,7 +662,10 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ cr_recv, /* recv decrypted data */
+ cr_send, /* send data to encrypt */
};
#endif /* USE_RUSTLS */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index e022a2c..7eab954 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -41,6 +41,7 @@
#include "schannel.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "strcase.h"
#include "sendf.h"
#include "connect.h" /* for the connect timeout */
@@ -185,11 +186,8 @@
#define PKCS12_NO_PERSIST_KEY 0x00008000
#endif
-static Curl_recv schannel_recv;
-static Curl_send schannel_send;
-
-static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *pinnedpubkey);
static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
@@ -209,18 +207,19 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
}
static CURLcode
-set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
- struct connectdata *conn)
+set_ssl_version_min_max(DWORD *enabled_protocols,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_DEFAULT:
-#if 0 /* Disabled in CMake due to issue 24147 (curl issue 9431) */
/* Windows Server 2022 and newer (including Windows 11) support TLS 1.3
built-in. Previous builds of Windows 10 had broken TLS 1.3
implementations that could be enabled via registry.
@@ -230,7 +229,6 @@ set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
}
else /* Windows 10 and older */
-#endif
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
@@ -249,7 +247,6 @@ set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
break;
case CURL_SSLVERSION_TLSv1_3:
-#if 0 /* Disabled in CMake due to issue 24147 (curl issue 9431) */
/* Windows Server 2022 and newer */
if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
@@ -260,16 +257,12 @@ set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11");
return CURLE_SSL_CONNECT_ERROR;
}
-#else
- failf(data, "schannel: TLS 1.3 is not yet supported");
- return CURLE_SSL_CONNECT_ERROR;
-#endif
}
}
return CURLE_OK;
}
-/*longest is 26, buffer is slightly bigger*/
+/* longest is 26, buffer is slightly bigger */
#define LONGEST_ALG_ID 32
#define CIPHEROPTION(X) \
if(strcmp(#X, tmp) == 0) \
@@ -296,7 +289,7 @@ get_alg_id_by_name(char *name)
CIPHEROPTION(CALG_MAC);
CIPHEROPTION(CALG_RSA_SIGN);
CIPHEROPTION(CALG_DSS_SIGN);
-/*ifdefs for the options that are defined conditionally in wincrypt.h*/
+/* ifdefs for the options that are defined conditionally in wincrypt.h */
#ifdef CALG_NO_SIGN
CIPHEROPTION(CALG_NO_SIGN);
#endif
@@ -484,11 +477,12 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
}
#endif
static CURLcode
-schannel_acquire_credential_handle(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+schannel_acquire_credential_handle(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
#ifdef HAS_CLIENT_CERT_PATH
PCCERT_CONTEXT client_certs[1] = { NULL };
@@ -505,7 +499,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
DEBUGASSERT(backend);
- if(conn->ssl_config.verifypeer) {
+ if(conn_config->verifypeer) {
#ifdef HAS_MANUAL_VERIFY_API
if(backend->use_manual_cred_validation)
flags = SCH_CRED_MANUAL_CRED_VALIDATION;
@@ -513,14 +507,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
#endif
flags = SCH_CRED_AUTO_CRED_VALIDATION;
- if(SSL_SET_OPTION(no_revoke)) {
+ if(ssl_config->no_revoke) {
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
DEBUGF(infof(data, "schannel: disabled server certificate revocation "
"checks"));
}
- else if(SSL_SET_OPTION(revoke_best_effort)) {
+ else if(ssl_config->revoke_best_effort) {
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
@@ -541,14 +535,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
"schannel: disabled server cert revocation checks"));
}
- if(!conn->ssl_config.verifyhost) {
+ if(!conn_config->verifyhost) {
flags |= SCH_CRED_NO_SERVERNAME_CHECK;
DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
"comparing the supplied target name with the subject "
"names in server certificates."));
}
- if(!SSL_SET_OPTION(auto_client_cert)) {
+ if(!ssl_config->auto_client_cert) {
flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
flags |= SCH_CRED_NO_DEFAULT_CREDS;
infof(data, "schannel: disabled automatic use of client certificate");
@@ -556,7 +550,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
else
infof(data, "schannel: enabled automatic use of client certificate");
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -564,7 +558,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- result = set_ssl_version_min_max(&enabled_protocols, data, conn);
+ result = set_ssl_version_min_max(&enabled_protocols, cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -819,7 +813,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
* disable all the ciphers and re-enable which
* ciphers the user has provided.
*/
- ciphers13 = SSL_CONN_CONFIG(cipher_list13);
+ ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
const int remaining_ciphers = 5;
@@ -1013,7 +1007,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
else {
/* Pre-Windows 10 1809 */
ALG_ID algIds[NUM_CIPHERS];
- char *ciphers = SSL_CONN_CONFIG(cipher_list);
+ char *ciphers = conn_config->cipher_list;
SCHANNEL_CRED schannel_cred = { 0 };
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
schannel_cred.dwFlags = flags;
@@ -1022,7 +1016,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(ciphers) {
result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
if(CURLE_OK != result) {
- failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
+ failf(data, "Unable to set ciphers to from connection ssl config");
return result;
}
}
@@ -1072,11 +1066,13 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
}
static CURLcode
-schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
ssize_t written = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
SecBuffer inbuf;
@@ -1091,14 +1087,12 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
struct in6_addr addr6;
#endif
CURLcode result;
- char * const hostname = SSL_HOST_NAME();
- struct ssl_backend_data *backend = connssl->backend;
+ const char *hostname = connssl->hostname;
DEBUGASSERT(backend);
-
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
- hostname, conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 1/3)",
+ hostname, connssl->port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1111,7 +1105,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */
- backend->use_alpn = conn->bits.tls_enable_alpn &&
+ backend->use_alpn = cf->conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
@@ -1130,7 +1124,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
- if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
+ if(conn_config->CAfile || conn_config->ca_info_blob) {
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
backend->use_manual_cred_validation = true;
@@ -1144,7 +1138,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
else
backend->use_manual_cred_validation = false;
#else
- if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
+ if(conn_config->CAfile || conn_config->ca_info_blob) {
failf(data, "schannel: CA cert support not built in");
return CURLE_NOT_BUILT_IN;
}
@@ -1154,11 +1148,9 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
backend->cred = NULL;
/* check for an existing re-usable credential handle */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- (void **)&old_cred, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: re-using existing credential handle"));
@@ -1173,13 +1165,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(!backend->cred) {
char *snihost;
- result = schannel_acquire_credential_handle(data, conn, sockindex);
+ result = schannel_acquire_credential_handle(cf, data);
if(result != CURLE_OK) {
return result;
}
/* A hostname associated with the credential is needed by
InitializeSecurityContext for SNI and other reasons. */
- snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ snihost = Curl_ssl_snihost(data, hostname, NULL);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -1207,18 +1199,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* The first four bytes will be an unsigned int indicating number
of bytes of data in the rest of the buffer. */
- extension_len = (unsigned int *)(&alpn_buffer[cur]);
+ extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
cur += sizeof(unsigned int);
/* The next four bytes are an indicator that this buffer will contain
ALPN data, as opposed to NPN, for example. */
- *(unsigned int *)&alpn_buffer[cur] =
+ *(unsigned int *)(void *)&alpn_buffer[cur] =
SecApplicationProtocolNegotiationExt_ALPN;
cur += sizeof(unsigned int);
/* The next two bytes will be an unsigned short indicating the number
of bytes used to list the preferred protocols. */
- list_len = (unsigned short*)(&alpn_buffer[cur]);
+ list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
cur += sizeof(unsigned short);
list_start_index = cur;
@@ -1261,7 +1253,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
- if(!SSL_SET_OPTION(auto_client_cert)) {
+ if(!ssl_config->auto_client_cert) {
backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
}
@@ -1321,8 +1313,9 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
"sending %lu bytes.", outbuf.cbBuffer));
/* send initial handshake data which is now stored in output buffer */
- result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
+ written = Curl_conn_cf_send(cf->next, data,
+ outbuf.pvBuffer, outbuf.cbBuffer,
+ &result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send initial handshake data: "
@@ -1346,12 +1339,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
int i;
ssize_t nread = -1, written = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
unsigned char *reallocated_buffer;
SecBuffer outbuf[3];
SecBufferDesc outbuf_desc;
@@ -1361,15 +1355,14 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
CURLcode result;
bool doread;
const char *pubkey_ptr;
- struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
- SSL_HOST_NAME(), conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 2/3)",
+ connssl->hostname, connssl->port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1419,12 +1412,12 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
for(;;) {
if(doread) {
/* read encrypted handshake data from socket */
- result = Curl_read_plain(conn->sock[sockindex],
+ nread = Curl_conn_cf_recv(cf->next, data,
(char *) (backend->encdata_buffer +
backend->encdata_offset),
backend->encdata_length -
backend->encdata_offset,
- &nread);
+ &result);
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
connssl->connecting_state = ssl_connect_2_reading;
@@ -1508,9 +1501,9 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
"sending %lu bytes.", outbuf[i].cbBuffer));
/* send handshake token to server */
- result = Curl_write_plain(data, conn->sock[sockindex],
- outbuf[i].pvBuffer, outbuf[i].cbBuffer,
- &written);
+ written = Curl_conn_cf_send(cf->next, data,
+ outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+ &result);
if((result != CURLE_OK) ||
(outbuf[i].cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send next handshake data: "
@@ -1603,9 +1596,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
- pubkey_ptr = SSL_PINNED_PUB_KEY();
+ pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(pubkey_ptr) {
- result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
+ result = pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
if(result) {
failf(data, "SSL: public key does not match pinned public key");
return result;
@@ -1613,8 +1608,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_MANUAL_VERIFY_API
- if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
- return Curl_verify_certificate(data, conn, sockindex);
+ if(conn_config->verifypeer && backend->use_manual_cred_validation) {
+ return Curl_verify_certificate(cf, data);
}
#endif
@@ -1681,28 +1676,24 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
}
static CURLcode
-schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
- bool isproxy = SSL_IS_PROXY();
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- const char * const hostname = SSL_HOST_NAME();
-#endif
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
#endif
- struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
- hostname, conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 3/3)",
+ connssl->hostname, connssl->port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1754,13 +1745,13 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
alpn = CURL_HTTP_VERSION_1_1;
}
if(backend->recv_renegotiating) {
- if(alpn != conn->alpn) {
+ if(alpn != cf->conn->alpn) {
failf(data, "schannel: server selected an ALPN protocol too late");
return CURLE_SSL_CONNECT_ERROR;
}
}
else
- conn->alpn = alpn;
+ cf->conn->alpn = alpn;
}
else {
if(!backend->recv_renegotiating)
@@ -1768,21 +1759,20 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
if(!backend->recv_renegotiating) {
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
#endif
/* save the current session data for possible re-use */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
- NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
if(incache) {
if(old_cred != backend->cred) {
DEBUGF(infof(data,
@@ -1793,9 +1783,9 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
+ result = Curl_ssl_addsessionid(cf, data, backend->cred,
sizeof(struct Curl_schannel_cred),
- sockindex, &added);
+ &added);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "schannel: failed to store credential handle");
@@ -1845,12 +1835,13 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, bool nonblocking, bool *done)
+schannel_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool nonblocking, bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1870,7 +1861,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
- result = schannel_connect_step1(data, conn, sockindex);
+ result = schannel_connect_step1(cf, data);
if(result)
return result;
}
@@ -1925,7 +1916,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- result = schannel_connect_step2(data, conn, sockindex);
+ result = schannel_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1935,22 +1926,13 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = schannel_connect_step3(data, conn, sockindex);
+ result = schannel_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- if(!connssl->backend->recv_renegotiating) {
- /* On renegotiation, we don't want to reset the existing recv/send
- * function pointers. They will have been set after the initial TLS
- * handshake was completed. If they were subsequently modified, as
- * is the case with HTTP/2, we don't want to override that change.
- */
- conn->recv[sockindex] = schannel_recv;
- conn->send[sockindex] = schannel_send;
- }
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
/* When SSPI is used in combination with Schannel
@@ -1961,7 +1943,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
{
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
- conn->sslContext = &backend->ctxt->ctxt_handle;
+ cf->conn->sslContext = &backend->ctxt->ctxt_handle;
}
#endif
@@ -1977,14 +1959,13 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
}
static ssize_t
-schannel_send(struct Curl_easy *data, int sockindex,
+schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
ssize_t written = -1;
size_t data_len = 0;
unsigned char *ptr = NULL;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
SecBuffer outbuf[4];
SecBufferDesc outbuf_desc;
SECURITY_STATUS sspi_status = SEC_E_OK;
@@ -2075,7 +2056,7 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
else if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
- what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
+ what = SOCKET_WRITABLE(cf->conn->sock[cf->sockindex], timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -2092,8 +2073,9 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
/* socket is writable */
- result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
- len - written, &this_write);
+ this_write = Curl_conn_cf_send(cf->next, data,
+ ptr + written, len - written,
+ &result);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
@@ -2123,13 +2105,12 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
static ssize_t
-schannel_recv(struct Curl_easy *data, int sockindex,
+schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
size_t size = 0;
ssize_t nread = -1;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
unsigned char *reallocated_buffer;
size_t reallocated_length;
bool done = FALSE;
@@ -2205,19 +2186,19 @@ schannel_recv(struct Curl_easy *data, int sockindex,
backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */
- *err = Curl_read_plain(conn->sock[sockindex],
- (char *)(backend->encdata_buffer +
+ nread = Curl_conn_cf_recv(cf->next, data,
+ (char *)(backend->encdata_buffer +
backend->encdata_offset),
- size, &nread);
+ size, err);
if(*err) {
nread = -1;
if(*err == CURLE_AGAIN)
DEBUGF(infof(data,
- "schannel: Curl_read_plain returned CURLE_AGAIN"));
+ "schannel: recv returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
- infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
+ infof(data, "schannel: recv returned CURLE_RECV_ERROR");
else
- infof(data, "schannel: Curl_read_plain returned error %d", *err);
+ infof(data, "schannel: recv returned error %d", *err);
}
else if(nread == 0) {
backend->recv_connection_closed = true;
@@ -2338,7 +2319,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
connssl->state = ssl_connection_negotiating;
connssl->connecting_state = ssl_connect_2_writing;
backend->recv_renegotiating = true;
- *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
+ *err = schannel_connect_common(cf, data, FALSE, &done);
backend->recv_renegotiating = false;
if(*err) {
infof(data, "schannel: renegotiation failed");
@@ -2446,20 +2427,20 @@ schannel_recv(struct Curl_easy *data, int sockindex,
return *err ? -1 : 0;
}
-static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return schannel_connect_common(data, conn, sockindex, TRUE, done);
+ return schannel_connect_common(cf, data, TRUE, done);
}
-static CURLcode schannel_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode schannel_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
+ result = schannel_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -2468,15 +2449,16 @@ static CURLcode schannel_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static bool schannel_data_pending(const struct connectdata *conn,
- int sockindex)
+static bool schannel_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
- if(connssl->use) /* SSL/TLS is in use */
+ if(connssl->backend->ctxt) /* SSL/TLS is in use */
return (backend->decdata_offset > 0 ||
(backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
else
@@ -2507,25 +2489,24 @@ static void schannel_session_free(void *ptr)
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
-static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int schannel_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
*/
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- char * const hostname = SSL_HOST_NAME();
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(data);
DEBUGASSERT(backend);
- if(connssl->use) {
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
- hostname, conn->remote_port);
+ if(connssl->backend->ctxt) {
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
+ connssl->hostname, connssl->port);
}
- if(connssl->use && backend->cred && backend->ctxt) {
+ if(backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
@@ -2566,10 +2547,9 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
/* send close message which is in output buffer */
- ssize_t written;
- result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
-
+ ssize_t written = Curl_conn_cf_send(cf->next, data,
+ outbuf.pvBuffer, outbuf.cbBuffer,
+ &result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
infof(data, "schannel: failed to send close msg: %s"
@@ -2611,14 +2591,9 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- if(conn->ssl[sockindex].use)
- /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
- Curl_ssl_shutdown(data, conn, sockindex);
- else
- schannel_shutdown(data, conn, sockindex);
+ schannel_shutdown(cf, data);
}
static int schannel_init(void)
@@ -2646,11 +2621,11 @@ static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
return Curl_win32_random(entropy, length);
}
-static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *pinnedpubkey)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CERT_CONTEXT *pCertContextServer = NULL;
@@ -2791,7 +2766,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
SSLSUPP_CAINFO_BLOB |
#endif
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -2805,7 +2781,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_cert_status_request, /* cert_status_request */
schannel_connect, /* connect */
schannel_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2816,7 +2792,10 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_false_start, /* false_start */
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ schannel_recv, /* recv decrypted data */
+ schannel_send, /* send data to encrypt */
};
#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
index 24d7eff..6d4235a 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.h
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -54,6 +54,7 @@
#include <schannel.h>
#include "curl_sspi.h"
+#include "cfilters.h"
#include "urldata.h"
/* <wincrypt.h> has been included via the above <schnlsp.h>.
@@ -77,14 +78,12 @@
extern const struct Curl_ssl Curl_ssl_schannel;
-CURLcode Curl_verify_certificate(struct Curl_easy *data,
- struct connectdata *conn, int sockindex);
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
/* structs to expose only in schannel.c and schannel_verify.c */
#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
-#include <wincrypt.h>
-
#ifdef __MINGW32__
#ifdef __MINGW64_VERSION_MAJOR
#define HAS_MANUAL_VERIFY_API
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 1ac1d3e..e499216 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -42,6 +42,7 @@
#ifdef HAS_MANUAL_VERIFY_API
#include "vtls.h"
+#include "vtls_int.h"
#include "sendf.h"
#include "strerror.h"
#include "curl_multibyte.h"
@@ -458,7 +459,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
static CURLcode verify_host(struct Curl_easy *data,
CERT_CONTEXT *pCertContextServer,
- const char * const conn_hostname)
+ const char *conn_hostname)
{
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
TCHAR *cert_hostname_buff = NULL;
@@ -562,17 +563,18 @@ cleanup:
return result;
}
-CURLcode Curl_verify_certificate(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SECURITY_STATUS sspi_status;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result = CURLE_OK;
CERT_CONTEXT *pCertContextServer = NULL;
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
- const char * const conn_hostname = SSL_HOST_NAME();
DEBUGASSERT(BACKEND);
@@ -589,7 +591,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
if(result == CURLE_OK &&
- (SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
+ (conn_config->CAfile || conn_config->ca_info_blob) &&
BACKEND->use_manual_cred_validation) {
/*
* Create a chain engine that uses the certificates in the CA file as
@@ -616,7 +618,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
result = CURLE_SSL_CACERT_BADFILE;
}
else {
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
if(ca_info_blob) {
result = add_certs_data_to_store(trust_store,
(const char *)ca_info_blob->data,
@@ -626,7 +628,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
else {
result = add_certs_file_to_store(trust_store,
- SSL_CONN_CONFIG(CAfile),
+ conn_config->CAfile,
data);
}
}
@@ -669,7 +671,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (SSL_SET_OPTION(no_revoke) ? 0 :
+ (ssl_config->no_revoke ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
@@ -718,8 +720,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
if(result == CURLE_OK) {
- if(SSL_CONN_CONFIG(verifyhost)) {
- result = verify_host(data, pCertContextServer, conn_hostname);
+ if(conn_config->verifyhost) {
+ result = verify_host(data, pCertContextServer, connssl->hostname);
}
}
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index c764e36..d903c53 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -122,12 +122,12 @@
#include <sys/sysctl.h>
#endif /* CURL_BUILD_MAC */
-#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "connect.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "sectransp.h"
#include "curl_printf.h"
#include "strdup.h"
@@ -136,13 +136,21 @@
/* The last #include file should be: */
#include "memdebug.h"
+
+#define DEBUG_CF 0
+
+#if DEBUG_CF
+#define CF_DEBUGF(x) x
+#else
+#define CF_DEBUGF(x) do { } while(0)
+#endif
+
/* From MacTypes.h (which we can't include because it isn't present in iOS: */
#define ioErr -36
#define paramErr -50
struct ssl_backend_data {
SSLContextRef ssl_ctx;
- curl_socket_t ssl_sockfd;
bool ssl_direction; /* true if writing, false if reading */
size_t ssl_write_buffered_length;
};
@@ -825,116 +833,73 @@ static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
#endif /* SECTRANSP_PINNEDPUBKEY */
-/* The following two functions were ripped from Apple sample code,
- * with some modifications: */
-static OSStatus SocketRead(SSLConnectionRef connection,
- void *data, /* owned by
- * caller, data
- * RETURNED */
- size_t *dataLength) /* IN/OUT */
+static OSStatus bio_cf_in_read(SSLConnectionRef connection,
+ void *buf,
+ size_t *dataLength) /* IN/OUT */
{
- size_t bytesToGo = *dataLength;
- size_t initLen = bytesToGo;
- UInt8 *currData = (UInt8 *)data;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- int sock;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
OSStatus rtn = noErr;
- size_t bytesRead;
- ssize_t rrtn;
- int theErr;
-
- DEBUGASSERT(backend);
- sock = backend->ssl_sockfd;
- *dataLength = 0;
- for(;;) {
- bytesRead = 0;
- rrtn = read(sock, currData, bytesToGo);
- if(rrtn <= 0) {
- /* this is guesswork... */
- theErr = errno;
- if(rrtn == 0) { /* EOF = server hung up */
- /* the framework will turn this into errSSLClosedNoNotify */
- rtn = errSSLClosedGraceful;
- }
- else /* do the switch */
- switch(theErr) {
- case ENOENT:
- /* connection closed */
- rtn = errSSLClosedGraceful;
- break;
- case ECONNRESET:
- rtn = errSSLClosedAbort;
- break;
- case EAGAIN:
- rtn = errSSLWouldBlock;
- backend->ssl_direction = false;
- break;
- default:
- rtn = ioErr;
- break;
- }
- break;
- }
- else {
- bytesRead = rrtn;
- }
- bytesToGo -= bytesRead;
- currData += bytesRead;
-
- if(bytesToGo == 0) {
- /* filled buffer with incoming data, done */
- break;
+ DEBUGASSERT(data);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
+ CF_DEBUGF(infof(data, CFMSG(cf, "bio_read(len=%zu) -> %zd, result=%d"),
+ *dataLength, nread, result));
+ if(nread < 0) {
+ switch(result) {
+ case CURLE_OK:
+ case CURLE_AGAIN:
+ rtn = errSSLWouldBlock;
+ backend->ssl_direction = false;
+ break;
+ default:
+ rtn = ioErr;
+ break;
}
+ nread = 0;
}
- *dataLength = initLen - bytesToGo;
-
+ else if((size_t)nread < *dataLength) {
+ rtn = errSSLWouldBlock;
+ }
+ *dataLength = nread;
return rtn;
}
-static OSStatus SocketWrite(SSLConnectionRef connection,
- const void *data,
- size_t *dataLength) /* IN/OUT */
+static OSStatus bio_cf_out_write(SSLConnectionRef connection,
+ const void *buf,
+ size_t *dataLength) /* IN/OUT */
{
- size_t bytesSent = 0;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- int sock;
- ssize_t length;
- size_t dataLen = *dataLength;
- const UInt8 *dataPtr = (UInt8 *)data;
- OSStatus ortn;
- int theErr;
-
- DEBUGASSERT(backend);
- sock = backend->ssl_sockfd;
- *dataLength = 0;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
+ OSStatus rtn = noErr;
- do {
- length = write(sock,
- (char *)dataPtr + bytesSent,
- dataLen - bytesSent);
- } while((length > 0) &&
- ( (bytesSent += length) < dataLen) );
-
- if(length <= 0) {
- theErr = errno;
- if(theErr == EAGAIN) {
- ortn = errSSLWouldBlock;
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
+ CF_DEBUGF(infof(data, CFMSG(cf, "bio_send(len=%zu) -> %zd, result=%d"),
+ *dataLength, nwritten, result));
+ if(nwritten <= 0) {
+ if(result == CURLE_AGAIN) {
+ rtn = errSSLWouldBlock;
backend->ssl_direction = true;
}
else {
- ortn = ioErr;
+ rtn = ioErr;
}
+ nwritten = 0;
}
- else {
- ortn = noErr;
+ else if((size_t)nwritten < *dataLength) {
+ rtn = errSSLWouldBlock;
}
- *dataLength = bytesSent;
- return ortn;
+ *dataLength = nwritten;
+ return rtn;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -1372,14 +1337,14 @@ static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
}
#endif
-static CURLcode
-set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
long max_supported_version_by_os;
DEBUGASSERT(backend);
@@ -1665,23 +1630,21 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode sectransp_connect_step1(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ssl_cablob = SSL_CONN_CONFIG(ca_info_blob);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ const struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ssl_cablob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- bool isproxy = SSL_IS_PROXY();
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
+ (ssl_cablob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ bool isproxy = Curl_ssl_cf_is_proxy(cf);
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1694,6 +1657,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
DEBUGASSERT(backend);
+ CF_DEBUGF(infof(data, CFMSG(cf, "connect_step1")));
GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
#endif /* CURL_BUILD_MAC */
@@ -1733,7 +1697,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
/* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax) {
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
@@ -1754,7 +1718,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -1773,7 +1737,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
kSSLProtocolAll,
false);
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
@@ -1791,7 +1755,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -1807,13 +1771,13 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#else
- if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) {
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
failf(data, "Your version of the OS does not support to set maximum"
" SSL/TLS version");
return CURLE_SSL_CONNECT_ERROR;
}
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -1841,7 +1805,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
@@ -1849,7 +1813,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!isproxy || !conn->bits.tunnel_proxy)
+ && (!isproxy || !cf->conn->bits.tunnel_proxy)
#endif
) {
CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2));
@@ -1872,7 +1836,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
#endif
- if(SSL_SET_OPTION(key)) {
+ if(ssl_config->key) {
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
"Transport. The private key must be in the Keychain.");
}
@@ -1891,17 +1855,17 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else
err = !noErr;
if((err != noErr) && (is_cert_file || is_cert_data)) {
- if(!SSL_SET_OPTION(cert_type))
+ if(!ssl_config->cert_type)
infof(data, "SSL: Certificate type not set, assuming "
"PKCS#12 format.");
- else if(!strcasecompare(SSL_SET_OPTION(cert_type), "P12")) {
+ else if(!strcasecompare(ssl_config->cert_type, "P12")) {
failf(data, "SSL: The Security framework only supports "
"loading identities that are in PKCS#12 format.");
return CURLE_SSL_CERTPROBLEM;
}
err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
- SSL_SET_OPTION(key_passwd),
+ ssl_config->key_passwd,
&cert_and_key);
}
@@ -1994,7 +1958,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#else
if(SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
- bool break_on_auth = !conn->ssl_config.verifypeer ||
+ bool break_on_auth = !conn_config->verifypeer ||
ssl_cafile || ssl_cablob;
err = SSLSetSessionOption(backend->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
@@ -2007,7 +1971,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else {
#if CURL_SUPPORT_MAC_10_8
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn->ssl_config.verifypeer?true:false);
+ conn_config->verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2016,7 +1980,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
#else
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn->ssl_config.verifypeer?true:false);
+ conn_config->verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2037,9 +2001,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
/* Configure hostname check. SNI is used if available.
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
- if(conn->ssl_config.verifyhost) {
+ if(conn_config->verifyhost) {
size_t snilen;
- char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -2052,9 +2016,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- if((Curl_inet_pton(AF_INET, hostname, &addr))
+ if((Curl_inet_pton(AF_INET, connssl->hostname, &addr))
#ifdef ENABLE_IPV6
- || (Curl_inet_pton(AF_INET6, hostname, &addr))
+ || (Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
#endif
) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
@@ -2065,7 +2029,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
infof(data, "WARNING: disabling hostname validation also disables SNI.");
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(ciphers) {
err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
}
@@ -2083,20 +2047,20 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
specifically doesn't want us doing that: */
if(SSLSetSessionOption) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
- !SSL_SET_OPTION(enable_beast));
+ !ssl_config->enable_beast);
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
- data->set.ssl.falsestart); /* false start support */
+ ssl_config->falsestart); /* false start support */
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
char *ssl_sessionid;
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, isproxy, (void **)&ssl_sessionid,
- &ssl_sessionid_len, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
+ &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -2112,9 +2076,10 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else {
CURLcode result;
ssl_sessionid =
- aprintf("%s:%d:%d:%s:%ld",
+ aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
- verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
+ verifypeer, conn_config->verifyhost, connssl->hostname,
+ connssl->port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -2124,8 +2089,8 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- ssl_sessionid_len, sockindex, NULL);
+ result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ ssl_sessionid_len, NULL);
Curl_ssl_sessionid_unlock(data);
if(result) {
failf(data, "failed to store ssl session");
@@ -2134,18 +2099,13 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
}
- err = SSLSetIOFuncs(backend->ssl_ctx, SocketRead, SocketWrite);
+ err = SSLSetIOFuncs(backend->ssl_ctx, bio_cf_in_read, bio_cf_out_write);
if(err != noErr) {
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
- /* pass the raw socket into the SSL layers */
- /* We need to store the FD in a constant memory address, because
- * SSLSetConnection() will not copy that address. I've found that
- * conn->sock[sockindex] may change on its own. */
- backend->ssl_sockfd = sockfd;
- err = SSLSetConnection(backend->ssl_ctx, connssl);
+ err = SSLSetConnection(backend->ssl_ctx, cf);
if(err != noErr) {
failf(data, "SSL: SSLSetConnection() failed: %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2291,7 +2251,8 @@ static int append_cert_to_array(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode verify_cert_buf(struct Curl_easy *data,
+static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const unsigned char *certbuf, size_t buflen,
SSLContextRef ctx)
{
@@ -2299,7 +2260,12 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
long res;
unsigned char *der;
size_t derlen, offset = 0;
-
+ OSStatus ret;
+ SecTrustResultType trust_eval;
+ CFMutableArrayRef array = NULL;
+ SecTrustRef trust = NULL;
+ CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ (void)cf;
/*
* Certbuf now contains the contents of the certificate file, which can be
* - a single DER certificate,
@@ -2309,11 +2275,11 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
* Go through certbuf, and convert any PEM certificate in it into DER
* format.
*/
- CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeArrayCallBacks);
+ array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if(!array) {
failf(data, "SSL: out of memory creating CA certificate array");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
while(offset < buflen) {
@@ -2325,10 +2291,10 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
*/
res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
if(res < 0) {
- CFRelease(array);
failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
n, offset);
- return CURLE_SSL_CACERT_BADFILE;
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto out;
}
offset += res;
@@ -2336,8 +2302,9 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
/* This is not a PEM file, probably a certificate in DER format. */
rc = append_cert_to_array(data, certbuf, buflen, array);
if(rc != CURLE_OK) {
- CFRelease(array);
- return rc;
+ CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed")));
+ result = rc;
+ goto out;
}
break;
}
@@ -2349,63 +2316,73 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
rc = append_cert_to_array(data, der, derlen, array);
free(der);
if(rc != CURLE_OK) {
- CFRelease(array);
- return rc;
+ CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed")));
+ result = rc;
+ goto out;
}
}
- SecTrustRef trust;
- OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
+ ret = SSLCopyPeerTrust(ctx, &trust);
if(!trust) {
failf(data, "SSL: error getting certificate chain");
- CFRelease(array);
- return CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
}
else if(ret != noErr) {
- CFRelease(array);
failf(data, "SSLCopyPeerTrust() returned error %d", ret);
- return CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
}
+ CF_DEBUGF(infof(data, CFMSG(cf, "setting %d trust anchors"), n));
ret = SecTrustSetAnchorCertificates(trust, array);
if(ret != noErr) {
- CFRelease(array);
- CFRelease(trust);
failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
- return CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
}
ret = SecTrustSetAnchorCertificatesOnly(trust, true);
if(ret != noErr) {
- CFRelease(array);
- CFRelease(trust);
failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
- return CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
}
- SecTrustResultType trust_eval = 0;
+ trust_eval = 0;
ret = SecTrustEvaluate(trust, &trust_eval);
- CFRelease(array);
- CFRelease(trust);
if(ret != noErr) {
failf(data, "SecTrustEvaluate() returned error %d", ret);
- return CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
}
switch(trust_eval) {
case kSecTrustResultUnspecified:
+ /* what does this really mean? */
+ CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Unspecified")));
+ result = CURLE_OK;
+ goto out;
case kSecTrustResultProceed:
- return CURLE_OK;
+ CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Proceed")));
+ result = CURLE_OK;
+ goto out;
case kSecTrustResultRecoverableTrustFailure:
+ failf(data, "SSL: peer not verified: RecoverableTrustFailure");
+ goto out;
case kSecTrustResultDeny:
+ failf(data, "SSL: peer not verified: Deny");
+ goto out;
default:
- failf(data, "SSL: certificate verification failed (result: %d)",
- trust_eval);
- return CURLE_PEER_FAILED_VERIFICATION;
+ failf(data, "SSL: perr not verified: result=%d", trust_eval);
+ goto out;
}
+
+out:
+ if(trust)
+ CFRelease(trust);
+ if(array)
+ CFRelease(array);
+ return result;
}
-static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
+static CURLcode verify_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data, const char *cafile,
const struct curl_blob *ca_info_blob,
SSLContextRef ctx)
{
@@ -2414,6 +2391,7 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
size_t buflen;
if(ca_info_blob) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from config blob")));
certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
if(!certbuf) {
return CURLE_OUT_OF_MEMORY;
@@ -2423,6 +2401,8 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
certbuf[ca_info_blob->len]='\0';
}
else if(cafile) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from file '%s'"),
+ cafile));
if(read_cert(cafile, &certbuf, &buflen) < 0) {
failf(data, "SSL: failed to read or invalid CA certificate");
return CURLE_SSL_CACERT_BADFILE;
@@ -2431,7 +2411,7 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
else
return CURLE_SSL_CACERT_BADFILE;
- result = verify_cert_buf(data, certbuf, buflen, ctx);
+ result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
free(certbuf);
return result;
}
@@ -2544,23 +2524,24 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
}
#endif /* SECTRANSP_PINNEDPUBKEY */
-static CURLcode
-sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
OSStatus err;
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
- const char * const hostname = SSL_HOST_NAME();
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
DEBUGASSERT(backend);
+ CF_DEBUGF(infof(data, CFMSG(cf, "connect_step2")));
/* Here goes nothing: */
+check_handshake:
err = SSLHandshake(backend->ssl_ctx);
if(err != noErr) {
@@ -2573,16 +2554,16 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* The below is errSSLServerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
- SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(ca_info_blob),
+ if((conn_config->CAfile || conn_config->ca_info_blob) &&
+ conn_config->verifypeer) {
+ CURLcode result = verify_cert(cf, data, conn_config->CAfile,
+ conn_config->ca_info_blob,
backend->ssl_ctx);
if(result)
return result;
}
/* the documentation says we need to call SSLHandshake() again */
- return sectransp_connect_step2(data, conn, sockindex);
+ goto check_handshake;
/* Problem with encrypt / decrypt */
case errSSLPeerDecodeError:
@@ -2684,7 +2665,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
host name: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
- "certificate did not match \"%s\"\n", conn->host.dispname);
+ "certificate did not match \"%s\"\n", connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
/* Problem with SSL / TLS negotiation */
@@ -2776,7 +2757,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
default:
/* May also return codes listed in Security Framework Result Codes */
failf(data, "Unknown SSL protocol error in connection to %s:%d",
- hostname, err);
+ connssl->hostname, err);
break;
}
return CURLE_SSL_CONNECT_ERROR;
@@ -2835,7 +2816,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFArrayRef alpnArr = NULL;
CFStringRef chosenProtocol = NULL;
@@ -2847,18 +2828,18 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(chosenProtocol &&
!CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(chosenProtocol &&
!CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
/* chosenProtocol is a reference to the string within alpnArr
@@ -2894,11 +2875,12 @@ add_cert_to_certinfo(struct Curl_easy *data,
}
static CURLcode
-collect_server_cert_single(struct Curl_easy *data,
+collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
SecCertificateRef server_cert,
CFIndex idx)
{
CURLcode result = CURLE_OK;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(data->set.verbose) {
char *certp;
@@ -2909,25 +2891,24 @@ collect_server_cert_single(struct Curl_easy *data,
}
}
#endif
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = add_cert_to_certinfo(data, server_cert, (int)idx);
return result;
}
/* This should be called during step3 of the connection at the earliest */
-static CURLcode
-collect_server_cert(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode collect_server_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const bool show_verbose_server_cert = data->set.verbose;
#else
const bool show_verbose_server_cert = false;
#endif
- CURLcode result = data->set.ssl.certinfo ?
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = ssl_config->certinfo ?
CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CFArrayRef server_certs = NULL;
SecCertificateRef server_cert;
@@ -2937,7 +2918,7 @@ collect_server_cert(struct Curl_easy *data,
DEBUGASSERT(backend);
- if(!show_verbose_server_cert && !data->set.ssl.certinfo)
+ if(!show_verbose_server_cert && !ssl_config->certinfo)
return CURLE_OK;
if(!backend->ssl_ctx)
@@ -2951,11 +2932,11 @@ collect_server_cert(struct Curl_easy *data,
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(trust);
}
@@ -2973,11 +2954,11 @@ collect_server_cert(struct Curl_easy *data,
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(trust);
}
@@ -2988,12 +2969,12 @@ collect_server_cert(struct Curl_easy *data,
/* Just in case SSLCopyPeerCertificates() returns null too... */
if(err == noErr && server_certs) {
count = CFArrayGetCount(server_certs);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
}
@@ -3005,11 +2986,11 @@ collect_server_cert(struct Curl_easy *data,
err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
if(err == noErr) {
count = CFArrayGetCount(server_certs);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
}
@@ -3017,16 +2998,16 @@ collect_server_cert(struct Curl_easy *data,
return result;
}
-static CURLcode
-sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ CF_DEBUGF(infof(data, CFMSG(cf, "connect_step3")));
/* There is no step 3!
* Well, okay, let's collect server certificates, and if verbose mode is on,
* let's print the details of the server certificates. */
- const CURLcode result = collect_server_cert(data, conn, sockindex);
+ const CURLcode result = collect_server_cert(cf, data);
if(result)
return result;
@@ -3034,19 +3015,14 @@ sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static Curl_recv sectransp_recv;
-static Curl_send sectransp_send;
-
static CURLcode
-sectransp_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -3065,7 +3041,7 @@ sectransp_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = sectransp_connect_step1(data, conn, sockindex);
+ result = sectransp_connect_step1(cf, data);
if(result)
return result;
}
@@ -3119,7 +3095,7 @@ sectransp_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- result = sectransp_connect_step2(data, conn, sockindex);
+ result = sectransp_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -3130,15 +3106,14 @@ sectransp_connect_common(struct Curl_easy *data,
if(ssl_connect_3 == connssl->connecting_state) {
- result = sectransp_connect_step3(data, conn, sockindex);
+ result = sectransp_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "connected")));
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = sectransp_recv;
- conn->send[sockindex] = sectransp_send;
*done = TRUE;
}
else
@@ -3150,20 +3125,20 @@ sectransp_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode sectransp_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return sectransp_connect_common(data, conn, sockindex, TRUE, done);
+ return sectransp_connect_common(cf, data, TRUE, done);
}
-static CURLcode sectransp_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode sectransp_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = sectransp_connect_common(data, conn, sockindex, FALSE, &done);
+ result = sectransp_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -3173,10 +3148,9 @@ static CURLcode sectransp_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void) data;
@@ -3184,6 +3158,7 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
DEBUGASSERT(backend);
if(backend->ssl_ctx) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "close")));
(void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLCreateContext)
@@ -3197,19 +3172,19 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
backend->ssl_ctx = NULL;
}
- backend->ssl_sockfd = 0;
}
-static int sectransp_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int sectransp_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread;
int what;
int rc;
char buf[120];
int loop = 10; /* avoid getting stuck */
+ CURLcode result;
DEBUGASSERT(backend);
@@ -3221,12 +3196,13 @@ static int sectransp_shutdown(struct Curl_easy *data,
return 0;
#endif
- sectransp_close(data, conn, sockindex);
+ sectransp_close(cf, data);
rc = 0;
- what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], SSL_SHUTDOWN_TIMEOUT);
+ CF_DEBUGF(infof(data, CFMSG(cf, "shutdown")));
while(loop--) {
if(what < 0) {
/* anything that gets here is fatally bad */
@@ -3243,19 +3219,17 @@ static int sectransp_shutdown(struct Curl_easy *data,
/* Something to read, let's do it and hope that it is the close
notify alert from the server. No way to SSL_Read now, so use read(). */
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
+ nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
if(nread < 0) {
- char buffer[STRERROR_LEN];
- failf(data, "read: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
+ failf(data, "read: %s", curl_easy_strerror(result));
rc = -1;
}
if(nread <= 0)
break;
- what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0);
}
return rc;
@@ -3285,16 +3259,19 @@ static size_t sectransp_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int sectransp_check_cxn(struct connectdata *conn)
+static int sectransp_check_cxn(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
OSStatus err;
SSLSessionState state;
+ (void)data;
DEBUGASSERT(backend);
if(backend->ssl_ctx) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "check connection")));
err = SSLGetSessionState(backend->ssl_ctx, &state);
if(err == noErr)
return state == kSSLConnected || state == kSSLHandshake;
@@ -3303,17 +3280,19 @@ static int sectransp_check_cxn(struct connectdata *conn)
return 0;
}
-static bool sectransp_data_pending(const struct connectdata *conn,
- int connindex)
+static bool sectransp_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ const struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
OSStatus err;
size_t buffer;
+ (void)data;
DEBUGASSERT(backend);
if(backend->ssl_ctx) { /* SSL is in use */
+ CF_DEBUGF(infof(data, CFMSG(cf, "data_pending")));
err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
if(err == noErr)
return buffer > 0UL;
@@ -3362,14 +3341,13 @@ static bool sectransp_false_start(void)
return FALSE;
}
-static ssize_t sectransp_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t sectransp_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
size_t processed = 0UL;
OSStatus err;
@@ -3431,15 +3409,15 @@ static ssize_t sectransp_send(struct Curl_easy *data,
return (ssize_t)processed;
}
-static ssize_t sectransp_recv(struct Curl_easy *data,
- int num,
+static ssize_t sectransp_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
char *buf,
size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t processed = 0UL;
OSStatus err;
@@ -3470,10 +3448,10 @@ static ssize_t sectransp_recv(struct Curl_easy *data,
/* The below is errSSLPeerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
- SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(ca_info_blob),
+ if((conn_config->CAfile || conn_config->ca_info_blob) &&
+ conn_config->verifypeer) {
+ CURLcode result = verify_cert(cf, data, conn_config->CAfile,
+ conn_config->ca_info_blob,
backend->ssl_ctx);
if(result)
return result;
@@ -3504,10 +3482,9 @@ const struct Curl_ssl Curl_ssl_sectransp = {
SSLSUPP_CAINFO_BLOB |
SSLSUPP_CERTINFO |
#ifdef SECTRANSP_PINNEDPUBKEY
- SSLSUPP_PINNEDPUBKEY,
-#else
- 0,
+ SSLSUPP_PINNEDPUBKEY |
#endif /* SECTRANSP_PINNEDPUBKEY */
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -3521,7 +3498,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_cert_status_request, /* cert_status_request */
sectransp_connect, /* connect */
sectransp_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -3532,7 +3509,10 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_false_start, /* false_start */
sectransp_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ sectransp_recv, /* recv decrypted data */
+ sectransp_send, /* send data to encrypt */
};
#ifdef __clang__
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 9dee5aa..873ee6b 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -51,8 +51,10 @@
#endif
#include "urldata.h"
+#include "cfilters.h"
#include "vtls.h" /* generic SSL protos etc */
+#include "vtls_int.h"
#include "slist.h"
#include "sendf.h"
#include "strcase.h"
@@ -150,11 +152,11 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
!Curl_timestrcmp(data->password, needle->password) &&
(data->authtype == needle->authtype) &&
#endif
- Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
- Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
- Curl_safe_strcasecompare(data->curves, needle->curves) &&
- Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) &&
- Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
+ strcasecompare(data->cipher_list, needle->cipher_list) &&
+ strcasecompare(data->cipher_list13, needle->cipher_list13) &&
+ strcasecompare(data->curves, needle->curves) &&
+ strcasecompare(data->CRLfile, needle->CRLfile) &&
+ strcasecompare(data->pinned_key, needle->pinned_key))
return TRUE;
return FALSE;
@@ -291,89 +293,68 @@ static bool ssl_prefs_check(struct Curl_easy *data)
return TRUE;
}
-#ifndef CURL_DISABLE_PROXY
-static CURLcode
-ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
+static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data)
{
- DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
- if(ssl_connection_complete == conn->ssl[sockindex].state &&
- !conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *pbdata;
-
- if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
- return CURLE_NOT_BUILT_IN;
-
- /* The pointers to the ssl backend data, which is opaque here, are swapped
- rather than move the contents. */
- pbdata = conn->proxy_ssl[sockindex].backend;
- conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
+ struct ssl_connect_data *ctx;
- DEBUGASSERT(pbdata != NULL);
+ (void)data;
+ ctx = calloc(1, sizeof(*ctx));
+ if(!ctx)
+ return NULL;
- memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
- memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data);
+ ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
+ if(!ctx->backend) {
+ free(ctx);
+ return NULL;
+ }
+ return ctx;
+}
- conn->ssl[sockindex].backend = pbdata;
+static void cf_ctx_free(struct ssl_connect_data *ctx)
+{
+ if(ctx) {
+ free(ctx->backend);
+ free(ctx);
}
- return CURLE_OK;
}
-#endif
-CURLcode
-Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void cf_ctx_set_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- CURLcode result;
+ if(cf->ctx)
+ ((struct ssl_connect_data *)cf->ctx)->call_data = data;
+}
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.proxy_ssl_connected[sockindex]) {
- result = ssl_connect_init_proxy(conn, sockindex);
- if(result)
- return result;
- }
-#endif
+static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result;
if(!ssl_prefs_check(data))
return CURLE_SSL_CONNECT_ERROR;
/* mark this is being ssl-enabled from here on. */
- conn->ssl[sockindex].use = TRUE;
- conn->ssl[sockindex].state = ssl_connection_negotiating;
+ connssl->state = ssl_connection_negotiating;
- result = Curl_ssl->connect_blocking(data, conn, sockindex);
+ result = Curl_ssl->connect_blocking(cf, data);
- if(!result)
+ if(!result) {
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
- else
- conn->ssl[sockindex].use = FALSE;
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
return result;
}
-CURLcode
-Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
- bool isproxy, int sockindex, bool *done)
+static CURLcode
+ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool *done)
{
- CURLcode result;
-
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.proxy_ssl_connected[sockindex]) {
- result = ssl_connect_init_proxy(conn, sockindex);
- if(result)
- return result;
- }
-#endif
if(!ssl_prefs_check(data))
return CURLE_SSL_CONNECT_ERROR;
/* mark this is being ssl requested from here on. */
- conn->ssl[sockindex].use = TRUE;
- result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
- if(result)
- conn->ssl[sockindex].use = FALSE;
- else if(*done && !isproxy)
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
- return result;
+ return Curl_ssl->connect_nonblocking(cf, data, done);
}
/*
@@ -398,42 +379,26 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
* Check if there's a session ID for the given connection in the cache, and if
* there's one suitable, it is provided. Returns TRUE when no entry matched.
*/
-bool Curl_ssl_getsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
void **ssl_sessionid,
- size_t *idsize, /* set 0 if unknown */
- int sockindex)
+ size_t *idsize) /* set 0 if unknown */
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct Curl_ssl_session *check;
size_t i;
long *general_age;
bool no_match = TRUE;
-#ifndef CURL_DISABLE_PROXY
- struct ssl_primary_config * const ssl_config = isProxy ?
- &conn->proxy_ssl_config :
- &conn->ssl_config;
- const char * const name = isProxy ?
- conn->http_proxy.host.name : conn->host.name;
- int port = isProxy ? (int)conn->port : conn->remote_port;
-#else
- /* no proxy support */
- struct ssl_primary_config * const ssl_config = &conn->ssl_config;
- const char * const name = conn->host.name;
- int port = conn->remote_port;
-#endif
- (void)sockindex;
*ssl_sessionid = NULL;
-
-#ifdef CURL_DISABLE_PROXY
- if(isProxy)
+ if(!ssl_config)
return TRUE;
-#endif
- DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+ DEBUGASSERT(ssl_config->primary.sessionid);
- if(!SSL_SET_OPTION(primary.sessionid) || !data->state.session)
+ if(!ssl_config->primary.sessionid || !data->state.session)
/* session ID re-use is disabled or the session cache has not been
setup */
return TRUE;
@@ -449,16 +414,16 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(name, check->name) &&
- ((!conn->bits.conn_to_host && !check->conn_to_host) ||
- (conn->bits.conn_to_host && check->conn_to_host &&
- strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
- ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
- (conn->bits.conn_to_port && check->conn_to_port != -1 &&
- conn->conn_to_port == check->conn_to_port)) &&
- (port == check->remote_port) &&
- strcasecompare(conn->handler->scheme, check->scheme) &&
- Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
+ if(strcasecompare(connssl->hostname, check->name) &&
+ ((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
+ (cf->conn->bits.conn_to_host && check->conn_to_host &&
+ strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
+ ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
+ (cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
+ cf->conn->conn_to_port == check->conn_to_port)) &&
+ (connssl->port == check->remote_port) &&
+ strcasecompare(cf->conn->handler->scheme, check->scheme) &&
+ Curl_ssl_config_matches(conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
(*general_age)++; /* increase general age */
check->age = *general_age; /* set this as used in this age */
@@ -470,10 +435,10 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
}
}
- DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+ DEBUGF(infof(data, DMSG(data, "%s Session ID in cache for %s %s://%s:%d"),
no_match? "Didn't find": "Found",
- isProxy ? "proxy" : "host",
- conn->handler->scheme, name, port));
+ Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
+ cf->conn->handler->scheme, connssl->hostname, connssl->port));
return no_match;
}
@@ -521,14 +486,15 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
* layer. Curl_XXXX_session_free() will be called to free/kill the session ID
* later on.
*/
-CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
void *ssl_sessionid,
size_t idsize,
- int sockindex,
bool *added)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t i;
struct Curl_ssl_session *store;
long oldest_age;
@@ -536,17 +502,6 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
char *clone_conn_to_host;
int conn_to_port;
long *general_age;
-#ifndef CURL_DISABLE_PROXY
- struct ssl_primary_config * const ssl_config = isProxy ?
- &conn->proxy_ssl_config :
- &conn->ssl_config;
- const char *hostname = isProxy ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- struct ssl_primary_config * const ssl_config = &conn->ssl_config;
- const char *hostname = conn->host.name;
-#endif
- (void)sockindex;
if(added)
*added = FALSE;
@@ -556,14 +511,15 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+ (void)ssl_config;
+ DEBUGASSERT(ssl_config->primary.sessionid);
- clone_host = strdup(hostname);
+ clone_host = strdup(connssl->hostname);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
- if(conn->bits.conn_to_host) {
- clone_conn_to_host = strdup(conn->conn_to_host.name);
+ if(cf->conn->bits.conn_to_host) {
+ clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
if(!clone_conn_to_host) {
free(clone_host);
return CURLE_OUT_OF_MEMORY; /* bail out */
@@ -572,8 +528,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
else
clone_conn_to_host = NULL;
- if(conn->bits.conn_to_port)
- conn_to_port = conn->conn_to_port;
+ if(cf->conn->bits.conn_to_port)
+ conn_to_port = cf->conn->conn_to_port;
else
conn_to_port = -1;
@@ -613,10 +569,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
- store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
- store->scheme = conn->handler->scheme;
+ store->remote_port = connssl->port;
+ store->scheme = cf->conn->handler->scheme;
- if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
+ if(!Curl_clone_primary_ssl_config(conn_config, &store->ssl_config)) {
Curl_free_primary_ssl_config(&store->ssl_config);
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
@@ -627,32 +583,16 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
if(added)
*added = TRUE;
- DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- isProxy ? "PROXY" : "server"));
+ DEBUGF(infof(data, DMSG(data, "Added Session ID to cache for %s://%s:%d"
+ " [%s]"), store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
return CURLE_OK;
}
-void Curl_ssl_associate_conn(struct Curl_easy *data,
- struct connectdata *conn)
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
{
- if(Curl_ssl->associate_connection) {
- Curl_ssl->associate_connection(data, conn, FIRSTSOCKET);
- if((conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) &&
- conn->bits.sock_accepted)
- Curl_ssl->associate_connection(data, conn, SECONDARYSOCKET);
- }
-}
-
-void Curl_ssl_detach_conn(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(Curl_ssl->disassociate_connection) {
- Curl_ssl->disassociate_connection(data, FIRSTSOCKET);
- if((conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) &&
- conn->bits.sock_accepted)
- Curl_ssl->disassociate_connection(data, SECONDARYSOCKET);
- }
+ if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
+ Curl_ssl->free_multi_ssl_backend_data(mbackend);
}
void Curl_ssl_close_all(struct Curl_easy *data)
@@ -671,47 +611,26 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_ssl->close_all(data);
}
-int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
+int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
+ (void)data;
if(connssl->connecting_state == ssl_connect_2_writing) {
/* write mode */
- socks[0] = conn->sock[FIRSTSOCKET];
+ socks[0] = cf->conn->sock[FIRSTSOCKET];
return GETSOCK_WRITESOCK(0);
}
if(connssl->connecting_state == ssl_connect_2_reading) {
/* read mode */
- socks[0] = conn->sock[FIRSTSOCKET];
+ socks[0] = cf->conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(0);
}
return GETSOCK_BLANK;
}
-void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
- Curl_ssl->close_one(data, conn, sockindex);
- conn->ssl[sockindex].state = ssl_connection_none;
-}
-
-CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- if(Curl_ssl->shut_down(data, conn, sockindex))
- return CURLE_SSL_SHUTDOWN_FAILED;
-
- conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
- conn->ssl[sockindex].state = ssl_connection_none;
-
- conn->recv[sockindex] = Curl_recv_plain;
- conn->send[sockindex] = Curl_send_plain;
-
- return CURLE_OK;
-}
-
/* Selects an SSL crypto engine
*/
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
@@ -774,15 +693,10 @@ void Curl_ssl_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_ssl_check_cxn(struct connectdata *conn)
+int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn)
{
- return Curl_ssl->check_cxn(conn);
-}
-
-bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex)
-{
- return Curl_ssl->data_pending(conn, connindex);
+ struct Curl_cfilter *cf = Curl_ssl_cf_get_ssl(conn->cfilter[FIRSTSOCKET]);
+ return cf? Curl_ssl->check_cxn(cf, data) : -1;
}
void Curl_ssl_free_certinfo(struct Curl_easy *data)
@@ -1138,20 +1052,13 @@ bool Curl_ssl_cert_status_request(void)
/*
* Check whether the SSL backend supports false start.
*/
-bool Curl_ssl_false_start(void)
+bool Curl_ssl_false_start(struct Curl_easy *data)
{
+ (void)data;
return Curl_ssl->false_start();
}
/*
- * Check whether the SSL backend supports setting TLS 1.3 cipher suites
- */
-bool Curl_ssl_tls13_ciphersuites(void)
-{
- return Curl_ssl->supports & SSLSUPP_TLS13_CIPHERSUITES;
-}
-
-/*
* Default implementations for unsupported functions.
*/
@@ -1163,19 +1070,18 @@ int Curl_none_init(void)
void Curl_none_cleanup(void)
{ }
-int Curl_none_shutdown(struct Curl_easy *data UNUSED_PARAM,
- struct connectdata *conn UNUSED_PARAM,
- int sockindex UNUSED_PARAM)
+int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
(void)data;
- (void)conn;
- (void)sockindex;
+ (void)cf;
return 0;
}
-int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM)
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- (void)conn;
+ (void)cf;
+ (void)data;
return -1;
}
@@ -1199,11 +1105,11 @@ void Curl_none_session_free(void *ptr UNUSED_PARAM)
(void)ptr;
}
-bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM,
- int connindex UNUSED_PARAM)
+bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM,
+ const struct Curl_easy *data UNUSED_PARAM)
{
- (void)conn;
- (void)connindex;
+ (void)cf;
+ (void)data;
return 0;
}
@@ -1244,28 +1150,30 @@ static int multissl_init(void)
return Curl_ssl->init();
}
-static CURLcode multissl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode multissl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
if(multissl_setup(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect_blocking(data, conn, sockindex);
+ return Curl_ssl->connect_blocking(cf, data);
}
-static CURLcode multissl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
if(multissl_setup(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
+ return Curl_ssl->connect_nonblocking(cf, data, done);
}
-static int multissl_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int multissl_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
{
if(multissl_setup(NULL))
return 0;
- return Curl_ssl->getsock(conn, socks);
+ return Curl_ssl->get_select_socks(cf, data, socks);
}
static void *multissl_get_internals(struct ssl_connect_data *connssl,
@@ -1276,12 +1184,30 @@ static void *multissl_get_internals(struct ssl_connect_data *connssl,
return Curl_ssl->get_internals(connssl, info);
}
-static void multissl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
if(multissl_setup(NULL))
return;
- Curl_ssl->close_one(data, conn, sockindex);
+ Curl_ssl->close(cf, data);
+}
+
+static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *code)
+{
+ if(multissl_setup(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->recv_plain(cf, data, buf, len, code);
+}
+
+static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *mem, size_t len,
+ CURLcode *code)
+{
+ if(multissl_setup(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->send_plain(cf, data, mem, len, code);
}
static const struct Curl_ssl Curl_ssl_multi = {
@@ -1299,7 +1225,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_cert_status_request, /* cert_status_request */
multissl_connect, /* connect */
multissl_connect_nonblocking, /* connect_nonblocking */
- multissl_getsock, /* getsock */
+ multissl_get_select_socks, /* getsock */
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1310,7 +1236,10 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ multissl_recv_plain, /* recv decrypted data */
+ multissl_send_plain, /* send data to encrypt */
};
const struct Curl_ssl *Curl_ssl =
@@ -1498,3 +1427,397 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
}
#endif /* !USE_SSL */
+
+#ifdef USE_SSL
+
+static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ /* TODO: close_one closes BOTH conn->ssl AND conn->proxy_ssl for this
+ * sockindex (if in use). Gladly, it is safe to call more than once. */
+ if(connssl) {
+ Curl_ssl->close(cf, data);
+ connssl->state = ssl_connection_none;
+ }
+ cf->connected = FALSE;
+}
+
+static void reinit_hostname(struct Curl_cfilter *cf)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+#ifndef CURL_DISABLE_PROXY
+ if(Curl_ssl_cf_is_proxy(cf)) {
+ /* TODO: there is not definition for a proxy setup on a secondary conn */
+ connssl->hostname = cf->conn->http_proxy.host.name;
+ connssl->dispname = cf->conn->http_proxy.host.dispname;
+ connssl->port = cf->conn->http_proxy.port;
+ }
+ else
+#endif
+ {
+ /* TODO: secondaryhostname is set to the IP address we connect to
+ * in the FTP handler, it is assumed that host verification uses the
+ * hostname from FIRSTSOCKET */
+ if(cf->sockindex == SECONDARYSOCKET && 0) {
+ connssl->hostname = cf->conn->secondaryhostname;
+ connssl->dispname = connssl->hostname;
+ connssl->port = cf->conn->secondary_port;
+ }
+ else {
+ connssl->hostname = cf->conn->host.name;
+ connssl->dispname = cf->conn->host.dispname;
+ connssl->port = cf->conn->remote_port;
+ }
+ }
+ DEBUGASSERT(connssl->hostname);
+}
+
+static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ cf_ctx_set_data(cf, data);
+ cf_close(cf, data);
+ cf_ctx_free(cf->ctx);
+ cf->ctx = NULL;
+}
+
+static void ssl_cf_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ cf_ctx_set_data(cf, data);
+ cf_close(cf, data);
+ cf->next->cft->close(cf->next, data);
+ cf_ctx_set_data(cf, NULL);
+}
+
+static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ cf_ctx_set_data(cf, data);
+ (void)connssl;
+ DEBUGASSERT(data->conn);
+ DEBUGASSERT(data->conn == cf->conn);
+ DEBUGASSERT(connssl);
+ DEBUGASSERT(cf->conn->host.name);
+
+ result = cf->next->cft->connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ goto out;
+
+ /* TODO: right now we do not fully control when hostname is set,
+ * assign it on each connect call. */
+ reinit_hostname(cf);
+ *done = FALSE;
+
+ if(blocking) {
+ result = ssl_connect(cf, data);
+ *done = (result == CURLE_OK);
+ }
+ else {
+ result = ssl_connect_nonblocking(cf, data, done);
+ }
+
+ if(!result && *done) {
+ cf->connected = TRUE;
+ if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+out:
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ bool result;
+
+ cf_ctx_set_data(cf, (struct Curl_easy *)data);
+ if(cf->ctx && Curl_ssl->data_pending(cf, data))
+ result = TRUE;
+ else
+ result = cf->next->cft->has_data_pending(cf->next, data);
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data, const void *buf, size_t len,
+ CURLcode *err)
+{
+ ssize_t nwritten;
+
+ *err = CURLE_OK;
+ cf_ctx_set_data(cf, data);
+ nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
+ cf_ctx_set_data(cf, NULL);
+ return nwritten;
+}
+
+static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, char *buf, size_t len,
+ CURLcode *err)
+{
+ ssize_t nread;
+
+ *err = CURLE_OK;
+ cf_ctx_set_data(cf, data);
+ nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
+ cf_ctx_set_data(cf, NULL);
+ return nread;
+}
+
+static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ int result;
+
+ cf_ctx_set_data(cf, data);
+ result = Curl_ssl->get_select_socks(cf, data, socks);
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static void ssl_cf_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ if(Curl_ssl->attach_data) {
+ cf_ctx_set_data(cf, data);
+ Curl_ssl->attach_data(cf, data);
+ cf_ctx_set_data(cf, NULL);
+ }
+}
+
+static void ssl_cf_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ if(Curl_ssl->detach_data) {
+ cf_ctx_set_data(cf, data);
+ Curl_ssl->detach_data(cf, data);
+ cf_ctx_set_data(cf, NULL);
+ }
+}
+
+static const struct Curl_cftype cft_ssl = {
+ "SSL",
+ CF_TYPE_SSL,
+ ssl_cf_destroy,
+ Curl_cf_def_setup,
+ ssl_cf_connect,
+ ssl_cf_close,
+ Curl_cf_def_get_host,
+ ssl_cf_get_select_socks,
+ ssl_cf_data_pending,
+ ssl_cf_send,
+ ssl_cf_recv,
+ ssl_cf_attach_data,
+ ssl_cf_detach_data,
+};
+
+static const struct Curl_cftype cft_ssl_proxy = {
+ "SSL-PROXY",
+ CF_TYPE_SSL,
+ ssl_cf_destroy,
+ Curl_cf_def_setup,
+ ssl_cf_connect,
+ ssl_cf_close,
+ Curl_cf_def_get_host,
+ ssl_cf_get_select_socks,
+ ssl_cf_data_pending,
+ ssl_cf_send,
+ ssl_cf_recv,
+ ssl_cf_attach_data,
+ ssl_cf_detach_data,
+};
+
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+ struct ssl_connect_data *ctx;
+ CURLcode result;
+
+ DEBUGASSERT(data->conn);
+ ctx = cf_ctx_new(data);
+ if(!ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = Curl_cf_create(&cf, &cft_ssl, ctx);
+ if(result)
+ goto out;
+
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+
+ result = CURLE_OK;
+
+out:
+ if(result)
+ cf_ctx_free(ctx);
+ return result;
+}
+
+#ifndef CURL_DISABLE_PROXY
+CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+ struct ssl_connect_data *ctx;
+ CURLcode result;
+
+ ctx = cf_ctx_new(data);
+ if(!ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = Curl_cf_create(&cf, &cft_ssl_proxy, ctx);
+ if(result)
+ goto out;
+
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+
+ result = CURLE_OK;
+
+out:
+ if(result)
+ cf_ctx_free(ctx);
+ return result;
+}
+
+#endif /* !CURL_DISABLE_PROXY */
+
+bool Curl_ssl_supports(struct Curl_easy *data, int option)
+{
+ (void)data;
+ return (Curl_ssl->supports & option)? TRUE : FALSE;
+}
+
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+ CURLINFO info, int n)
+{
+ void *result = NULL;
+ (void)n;
+ if(data->conn) {
+ struct Curl_cfilter *cf;
+ /* get first filter in chain, if any is present */
+ cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]);
+ if(cf) {
+ cf_ctx_set_data(cf, data);
+ result = Curl_ssl->get_internals(cf->ctx, info);
+ cf_ctx_set_data(cf, NULL);
+ }
+ }
+ return result;
+}
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+ int sockindex)
+{
+ struct Curl_cfilter *cf = data->conn? data->conn->cfilter[sockindex] : NULL;
+ CURLcode result = CURLE_OK;
+
+ (void)data;
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl) {
+ if(Curl_ssl->shut_down(cf, data))
+ result = CURLE_SSL_SHUTDOWN_FAILED;
+ Curl_conn_cf_discard(cf, data);
+ break;
+ }
+ }
+ return result;
+}
+
+static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf, *lowest_ssl_cf = NULL;
+
+ for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy) {
+ lowest_ssl_cf = cf;
+ if(cf->connected || (cf->next && cf->next->connected)) {
+ /* connected or about to start */
+ return cf;
+ }
+ }
+ }
+ return lowest_ssl_cf;
+}
+
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
+{
+ return (cf->cft == &cft_ssl_proxy);
+}
+
+struct ssl_config_data *
+Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+#ifdef CURL_DISABLE_PROXY
+ (void)cf;
+ return &data->set.ssl;
+#else
+ return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
+#endif
+}
+
+struct ssl_config_data *
+Curl_ssl_get_config(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ (void)data;
+ DEBUGASSERT(data->conn);
+ cf = get_ssl_cf_engaged(data->conn, sockindex);
+ return cf? Curl_ssl_cf_get_config(cf, data) : &data->set.ssl;
+}
+
+struct ssl_primary_config *
+Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
+{
+#ifdef CURL_DISABLE_PROXY
+ return &cf->conn->ssl_config;
+#else
+ return Curl_ssl_cf_is_proxy(cf)?
+ &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
+#endif
+}
+
+struct ssl_primary_config *
+Curl_ssl_get_primary_config(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ (void)data;
+ DEBUGASSERT(conn);
+ cf = get_ssl_cf_engaged(conn, sockindex);
+ return cf? Curl_ssl_cf_get_primary_config(cf) : NULL;
+}
+
+struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf)
+{
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy)
+ return cf;
+ }
+ return NULL;
+}
+
+#endif /* USE_SSL */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 50c53b3..5ad64fc 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -26,7 +26,10 @@
#include "curl_setup.h"
struct connectdata;
+struct ssl_config_data;
struct ssl_connect_data;
+struct ssl_primary_config;
+struct Curl_ssl_session;
#define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */
#define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */
@@ -47,98 +50,13 @@ struct ssl_connect_data;
#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \
ALPN_ACCEPTED "%.*s"
-struct Curl_ssl {
- /*
- * This *must* be the first entry to allow returning the list of available
- * backends in curl_global_sslset().
- */
- curl_ssl_backend info;
- unsigned int supports; /* bitfield, see above */
- size_t sizeof_ssl_backend_data;
-
- int (*init)(void);
- void (*cleanup)(void);
-
- size_t (*version)(char *buffer, size_t size);
- int (*check_cxn)(struct connectdata *cxn);
- int (*shut_down)(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
- bool (*data_pending)(const struct connectdata *conn,
- int connindex);
-
- /* return 0 if a find random is filled in */
- CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
- bool (*cert_status_request)(void);
-
- CURLcode (*connect_blocking)(struct Curl_easy *data,
- struct connectdata *conn, int sockindex);
- CURLcode (*connect_nonblocking)(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
- bool *done);
-
- /* If the SSL backend wants to read or write on this connection during a
- handshake, set socks[0] to the connection's FIRSTSOCKET, and return
- a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
- GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
- Mandatory. */
- int (*getsock)(struct connectdata *conn, curl_socket_t *socks);
-
- void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
- void (*close_one)(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
- void (*close_all)(struct Curl_easy *data);
- void (*session_free)(void *ptr);
-
- CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
- CURLcode (*set_engine_default)(struct Curl_easy *data);
- struct curl_slist *(*engines_list)(struct Curl_easy *data);
-
- bool (*false_start)(void);
- CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
- unsigned char *sha256sum, size_t sha256sumlen);
-
- bool (*associate_connection)(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex);
- void (*disassociate_connection)(struct Curl_easy *data, int sockindex);
-};
-
-#ifdef USE_SSL
-extern const struct Curl_ssl *Curl_ssl;
-#endif
-
-int Curl_none_init(void);
-void Curl_none_cleanup(void);
-int Curl_none_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-int Curl_none_check_cxn(struct connectdata *conn);
-CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
-void Curl_none_close_all(struct Curl_easy *data);
-void Curl_none_session_free(void *ptr);
-bool Curl_none_data_pending(const struct connectdata *conn, int connindex);
-bool Curl_none_cert_status_request(void);
-CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
-CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
-struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
-bool Curl_none_false_start(void);
-bool Curl_ssl_tls13_ciphersuites(void);
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+ backend */
+struct multi_ssl_backend_data;
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
const curl_ssl_backend ***avail);
-#include "openssl.h" /* OpenSSL versions */
-#include "gtls.h" /* GnuTLS versions */
-#include "nssg.h" /* NSS versions */
-#include "gskit.h" /* Global Secure ToolKit versions */
-#include "wolfssl.h" /* wolfSSL versions */
-#include "schannel.h" /* Schannel SSPI version */
-#include "sectransp.h" /* SecureTransport (Darwin) version */
-#include "mbedtls.h" /* mbedTLS versions */
-#include "bearssl.h" /* BearSSL versions */
-#include "rustls.h" /* rustls versions */
-
#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
#endif
@@ -153,40 +71,6 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
#define ALPN_H2_LENGTH 2
#define ALPN_H2 "h2"
-/* set of helper macros for the backends to access the correct fields. For the
- proxy or for the remote host - to properly support HTTPS proxy */
-#ifndef CURL_DISABLE_PROXY
-#define SSL_IS_PROXY() \
- (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
- ssl_connection_complete != \
- conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
- CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
-#define SSL_SET_OPTION(var) \
- (SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var)
-#define SSL_SET_OPTION_LVALUE(var) \
- (*(SSL_IS_PROXY() ? &data->set.proxy_ssl.var : &data->set.ssl.var))
-#define SSL_CONN_CONFIG(var) \
- (SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var)
-#define SSL_HOST_NAME() \
- (SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name)
-#define SSL_HOST_DISPNAME() \
- (SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname)
-#define SSL_HOST_PORT() \
- (SSL_IS_PROXY() ? conn->port : conn->remote_port)
-#define SSL_PINNED_PUB_KEY() (SSL_IS_PROXY() \
- ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] \
- : data->set.str[STRING_SSL_PINNEDPUBLICKEY])
-#else
-#define SSL_IS_PROXY() FALSE
-#define SSL_SET_OPTION(var) data->set.ssl.var
-#define SSL_SET_OPTION_LVALUE(var) data->set.ssl.var
-#define SSL_CONN_CONFIG(var) conn->ssl_config.var
-#define SSL_HOST_NAME() conn->host.name
-#define SSL_HOST_DISPNAME() conn->host.dispname
-#define SSL_HOST_PORT() conn->remote_port
-#define SSL_PINNED_PUB_KEY() \
- data->set.str[STRING_SSL_PINNEDPUBLICKEY]
-#endif
char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen);
bool Curl_ssl_config_matches(struct ssl_primary_config *data,
@@ -194,31 +78,15 @@ bool Curl_ssl_config_matches(struct ssl_primary_config *data,
bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
struct ssl_primary_config *dest);
void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
-/* An implementation of the getsock field of Curl_ssl that relies
- on the ssl_connect_state enum. Asks for read or write depending
- on whether conn->state is ssl_connect_2_reading or
- ssl_connect_2_writing. */
-int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks);
curl_sslbackend Curl_ssl_backend(void);
#ifdef USE_SSL
int Curl_ssl_init(void);
void Curl_ssl_cleanup(void);
-CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- bool isproxy,
- int sockindex,
- bool *done);
/* tell the SSL stuff to close down all open information regarding
connections (and thus session ID caching etc) */
void Curl_ssl_close_all(struct Curl_easy *data);
-void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
/* Sets engine as default for all SSL operations */
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
@@ -227,9 +95,7 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
/* init the SSL session ID cache */
CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
void Curl_ssl_version(char *buffer, size_t size);
-bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex);
-int Curl_ssl_check_cxn(struct connectdata *conn);
+int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn);
/* Certificate information list handling. */
@@ -255,30 +121,6 @@ void Curl_ssl_sessionid_lock(struct Curl_easy *data);
/* Unlock session cache mutex */
void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
-/* extract a session ID
- * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
- * Caller must make sure that the ownership of returned sessionid object
- * is properly taken (e.g. its refcount is incremented
- * under sessionid mutex).
- */
-bool Curl_ssl_getsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
- void **ssl_sessionid,
- size_t *idsize, /* set 0 if unknown */
- int sockindex);
-/* add a new session ID
- * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
- * Caller must ensure that it has properly shared ownership of this sessionid
- * object with cache (e.g. incrementing refcount on success)
- */
-CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
- void *ssl_sessionid,
- size_t idsize,
- int sockindex,
- bool *added);
/* Kill a single session ID entry in the cache
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* This will call engine-specific curlssl_session_free function, which must
@@ -304,41 +146,90 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
bool Curl_ssl_cert_status_request(void);
-bool Curl_ssl_false_start(void);
+bool Curl_ssl_false_start(struct Curl_easy *data);
-void Curl_ssl_associate_conn(struct Curl_easy *data,
- struct connectdata *conn);
-void Curl_ssl_detach_conn(struct Curl_easy *data,
- struct connectdata *conn);
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+ int sockindex);
+
+#ifndef CURL_DISABLE_PROXY
+CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+#endif /* !CURL_DISABLE_PROXY */
+
+/**
+ * Get the SSL configuration that is used on the connection.
+ * This returns NULL if no SSL is configured.
+ * Otherwise it returns the config of the first (highest) one that is
+ * either connected, in handshake or about to start
+ * (e.g. all filters below it are connected). If SSL filters are present,
+ * but neither can start operating, return the config of the lowest one
+ * that will first come into effect when connecting.
+ */
+struct ssl_config_data *Curl_ssl_get_config(struct Curl_easy *data,
+ int sockindex);
+
+/**
+ * Get the primary SSL configuration from the connection.
+ * This returns NULL if no SSL is configured.
+ * Otherwise it returns the config of the first (highest) one that is
+ * either connected, in handshake or about to start
+ * (e.g. all filters below it are connected). If SSL filters are present,
+ * but neither can start operating, return the config of the lowest one
+ * that will first come into effect when connecting.
+ */
+struct ssl_primary_config *
+Curl_ssl_get_primary_config(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+/**
+ * True iff the underlying SSL implementation supports the option.
+ * Option is one of the defined SSLSUPP_* values.
+ * `data` maybe NULL for the features of the default implementation.
+ */
+bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
+
+/**
+ * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
+ * chain at `sockindex` of type specified by `info`.
+ * For `n` == 0, the first active (top down) instance is returned.
+ * 1 gives the second active, etc.
+ * NULL is returned when no active SSL filter is present.
+ */
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+ CURLINFO info, int n);
+
#else /* if not USE_SSL */
/* When SSL support is not present, just define away these function calls */
#define Curl_ssl_init() 1
#define Curl_ssl_cleanup() Curl_nop_stmt
-#define Curl_ssl_connect(x,y,z) CURLE_NOT_BUILT_IN
#define Curl_ssl_close_all(x) Curl_nop_stmt
-#define Curl_ssl_close(x,y,z) Curl_nop_stmt
-#define Curl_ssl_shutdown(x,y,z) CURLE_NOT_BUILT_IN
#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
#define Curl_ssl_engines_list(x) NULL
-#define Curl_ssl_send(a,b,c,d,e) -1
-#define Curl_ssl_recv(a,b,c,d,e) -1
#define Curl_ssl_initsessions(x,y) CURLE_OK
-#define Curl_ssl_data_pending(x,y) 0
-#define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_check_cxn(d,x) 0
#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z,w,a) CURLE_NOT_BUILT_IN
#define Curl_ssl_kill_session(x) Curl_nop_stmt
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
#define Curl_ssl_cert_status_request() FALSE
-#define Curl_ssl_false_start() FALSE
-#define Curl_ssl_tls13_ciphersuites() FALSE
-#define Curl_ssl_associate_conn(a,b) Curl_nop_stmt
-#define Curl_ssl_detach_conn(a,b) Curl_nop_stmt
+#define Curl_ssl_false_start(a) FALSE
+#define Curl_ssl_get_internals(a,b,c,d) NULL
+#define Curl_ssl_supports(a,b) FALSE
+#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_ssl_cfilter_proxy_add(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_ssl_get_config(a,b) NULL
+#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
#endif
#endif /* HEADER_CURL_VTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h
new file mode 100644
index 0000000..6710a2b
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/vtls_int.h
@@ -0,0 +1,190 @@
+#ifndef HEADER_CURL_VTLS_INT_H
+#define HEADER_CURL_VTLS_INT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include "cfilters.h"
+#include "urldata.h"
+
+#ifdef USE_SSL
+
+/* Information in each SSL cfilter context: cf->ctx */
+struct ssl_connect_data {
+ ssl_connection_state state;
+ ssl_connect_state connecting_state;
+ const char *hostname; /* hostnaem for verification */
+ const char *dispname; /* display version of hostname */
+ int port; /* remote port at origin */
+ struct ssl_backend_data *backend; /* vtls backend specific props */
+ struct Curl_easy *call_data; /* data handle used in current call,
+ * same as parameter passed, but available
+ * here for backend internal callbacks
+ * that need it. NULLed after at the
+ * end of each vtls filter invcocation. */
+};
+
+
+/* Definitions for SSL Implementations */
+
+struct Curl_ssl {
+ /*
+ * This *must* be the first entry to allow returning the list of available
+ * backends in curl_global_sslset().
+ */
+ curl_ssl_backend info;
+ unsigned int supports; /* bitfield, see above */
+ size_t sizeof_ssl_backend_data;
+
+ int (*init)(void);
+ void (*cleanup)(void);
+
+ size_t (*version)(char *buffer, size_t size);
+ int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ int (*shut_down)(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+ bool (*data_pending)(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+
+ /* return 0 if a find random is filled in */
+ CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+ bool (*cert_status_request)(void);
+
+ CURLcode (*connect_blocking)(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+ CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done);
+
+ /* If the SSL backend wants to read or write on this connection during a
+ handshake, set socks[0] to the connection's FIRSTSOCKET, and return
+ a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
+ GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
+ Mandatory. */
+ int (*get_select_socks)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks);
+
+ void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
+ void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ void (*close_all)(struct Curl_easy *data);
+ void (*session_free)(void *ptr);
+
+ CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
+ CURLcode (*set_engine_default)(struct Curl_easy *data);
+ struct curl_slist *(*engines_list)(struct Curl_easy *data);
+
+ bool (*false_start)(void);
+ CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
+ unsigned char *sha256sum, size_t sha256sumlen);
+
+ bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+
+ void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);
+
+ ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *code);
+ ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *mem, size_t len, CURLcode *code);
+
+};
+
+extern const struct Curl_ssl *Curl_ssl;
+
+
+int Curl_none_init(void);
+void Curl_none_cleanup(void);
+int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+void Curl_none_close_all(struct Curl_easy *data);
+void Curl_none_session_free(void *ptr);
+bool Curl_none_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+bool Curl_none_cert_status_request(void);
+CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
+bool Curl_none_false_start(void);
+int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks);
+
+/**
+ * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
+ */
+struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/**
+ * Get the primary config relevant for the filter from its connection.
+ */
+struct ssl_primary_config *
+ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
+
+/**
+ * Get the first SSL filter in the chain starting with `cf`, or NULL.
+ */
+struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf);
+
+/**
+ * Get the SSL filter below the given one or NULL if there is none.
+ */
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void **ssl_sessionid,
+ size_t *idsize); /* set 0 if unknown */
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *ssl_sessionid,
+ size_t idsize,
+ bool *added);
+
+#include "openssl.h" /* OpenSSL versions */
+#include "gtls.h" /* GnuTLS versions */
+#include "nssg.h" /* NSS versions */
+#include "gskit.h" /* Global Secure ToolKit versions */
+#include "wolfssl.h" /* wolfSSL versions */
+#include "schannel.h" /* Schannel SSPI version */
+#include "sectransp.h" /* SecureTransport (Darwin) version */
+#include "mbedtls.h" /* mbedTLS versions */
+#include "bearssl.h" /* BearSSL versions */
+#include "rustls.h" /* rustls versions */
+
+#endif /* USE_SSL */
+
+#endif /* HEADER_CURL_VTLS_INT_H */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 594c39a..7cc4774 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -55,6 +55,7 @@
#include "sendf.h"
#include "inet_pton.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "keylog.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
@@ -84,14 +85,17 @@
#endif
#endif
+#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
+#define USE_BIO_CHAIN
+#else
+#undef USE_BIO_CHAIN
+#endif
+
struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
};
-static Curl_recv wolfssl_recv;
-static Curl_send wolfssl_send;
-
#ifdef OPENSSL_EXTRA
/*
* Availability note:
@@ -241,19 +245,130 @@ static const struct group_name_map gnm[] = {
};
#endif
+#ifdef USE_BIO_CHAIN
+
+static int bio_cf_create(WOLFSSL_BIO *bio)
+{
+ wolfSSL_BIO_set_shutdown(bio, 1);
+ wolfSSL_BIO_set_init(bio, 1);
+ wolfSSL_BIO_set_data(bio, NULL);
+ return 1;
+}
+
+static int bio_cf_destroy(WOLFSSL_BIO *bio)
+{
+ if(!bio)
+ return 0;
+ return 1;
+}
+
+static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ long ret = 1;
+
+ (void)cf;
+ (void)ptr;
+ switch(cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)wolfSSL_BIO_get_shutdown(bio);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ wolfSSL_BIO_set_shutdown(bio, (int)num);
+ break;
+ case BIO_CTRL_FLUSH:
+ /* we do no delayed writes, but if we ever would, this
+ * needs to trigger it. */
+ ret = 1;
+ break;
+ case BIO_CTRL_DUP:
+ ret = 1;
+ break;
+#ifdef BIO_CTRL_EOF
+ case BIO_CTRL_EOF:
+ /* EOF has been reached on input? */
+ return (!cf->next || !cf->next->connected);
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
+{
+ struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ wolfSSL_BIO_clear_retry_flags(bio);
+ if(nwritten < 0 && CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ return (int)nwritten;
+}
+
+static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
+{
+ struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ wolfSSL_BIO_clear_retry_flags(bio);
+ if(nread < 0 && CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ return (int)nread;
+}
+
+static WOLFSSL_BIO_METHOD *bio_cf_method = NULL;
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+ wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
+ wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
+ wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
+ wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create);
+ wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
+}
+
+static void bio_cf_free_methods(void)
+{
+ wolfSSL_BIO_meth_free(bio_cf_method);
+}
+
+#else /* USE_BIO_CHAIN */
+
+#define bio_cf_init_methods() Curl_nop_stmt
+#define bio_cf_free_methods() Curl_nop_stmt
+
+#endif /* !USE_BIO_CHAIN */
+
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
*/
static CURLcode
-wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
char *ciphers, *curves;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SSL_METHOD* req_method = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
#ifdef HAVE_LIBOQS
word16 oqsAlg = 0;
size_t idx = 0;
@@ -270,13 +385,13 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(connssl->state == ssl_connection_complete)
return CURLE_OK;
- if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
return CURLE_SSL_CONNECT_ERROR;
}
/* check to see if we've been told to use an explicit SSL/TLS version */
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
@@ -339,7 +454,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
@@ -363,7 +478,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
break;
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(ciphers) {
if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
@@ -372,7 +487,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "Cipher selection: %s", ciphers);
}
- curves = SSL_CONN_CONFIG(curves);
+ curves = conn_config->curves;
if(curves) {
#ifdef HAVE_LIBOQS
@@ -394,18 +509,18 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#ifndef NO_FILESYSTEM
/* load trusted cacert */
- if(SSL_CONN_CONFIG(CAfile)) {
+ if(conn_config->CAfile) {
if(1 != SSL_CTX_load_verify_locations(backend->ctx,
- SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(CApath))) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ conn_config->CAfile,
+ conn_config->CApath)) {
+ if(conn_config->verifypeer) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
" CAfile: %s CApath: %s",
- SSL_CONN_CONFIG(CAfile)?
- SSL_CONN_CONFIG(CAfile): "none",
- SSL_CONN_CONFIG(CApath)?
- SSL_CONN_CONFIG(CApath) : "none");
+ conn_config->CAfile?
+ conn_config->CAfile: "none",
+ conn_config->CApath?
+ conn_config->CApath : "none");
return CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -420,25 +535,25 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "successfully set certificate verify locations:");
}
infof(data, " CAfile: %s",
- SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
+ conn_config->CAfile ? conn_config->CAfile : "none");
infof(data, " CApath: %s",
- SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
+ conn_config->CApath ? conn_config->CApath : "none");
}
/* Load the client certificate, and private key */
- if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
- int file_type = do_file_type(SSL_SET_OPTION(cert_type));
+ if(ssl_config->primary.clientcert && ssl_config->key) {
+ int file_type = do_file_type(ssl_config->cert_type);
if(SSL_CTX_use_certificate_file(backend->ctx,
- SSL_SET_OPTION(primary.clientcert),
+ ssl_config->primary.clientcert,
file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
" phrase?)");
return CURLE_SSL_CONNECT_ERROR;
}
- file_type = do_file_type(SSL_SET_OPTION(key_type));
- if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
+ file_type = do_file_type(ssl_config->key_type);
+ if(SSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
@@ -451,8 +566,8 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
SSL_CTX_set_verify(backend->ctx,
- SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
- SSL_VERIFY_NONE,
+ conn_config->verifypeer?SSL_VERIFY_PEER:
+ SSL_VERIFY_NONE,
NULL);
#ifdef HAVE_SNI
@@ -461,16 +576,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
- const char * const hostname = SSL_HOST_NAME();
- size_t hostname_len = strlen(hostname);
+ size_t hostname_len = strlen(connssl->hostname);
+
if((hostname_len < USHRT_MAX) &&
- !Curl_inet_pton(AF_INET, hostname, &addr4)
+ !Curl_inet_pton(AF_INET, connssl->hostname, &addr4)
#ifdef ENABLE_IPV6
- && !Curl_inet_pton(AF_INET6, hostname, &addr6)
+ && !Curl_inet_pton(AF_INET6, connssl->hostname, &addr6)
#endif
) {
size_t snilen;
- char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
if(!snihost ||
wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
(unsigned short)snilen) != 1) {
@@ -491,7 +606,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
}
#ifdef NO_FILESYSTEM
- else if(SSL_CONN_CONFIG(verifypeer)) {
+ else if(conn_config->verifypeer) {
failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
@@ -518,7 +633,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#ifdef HAVE_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
char protocols[128];
*protocols = '\0';
@@ -563,13 +678,11 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif /* HAVE_SECURE_RENEGOTIATION */
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
@@ -581,11 +694,24 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
Curl_ssl_sessionid_unlock(data);
}
+#ifdef USE_BIO_CHAIN
+ {
+ WOLFSSL_BIO *bio;
+
+ bio = BIO_new(bio_cf_method);
+ if(!bio)
+ return CURLE_OUT_OF_MEMORY;
+
+ wolfSSL_BIO_set_data(bio, cf);
+ wolfSSL_set_bio(backend->handle, bio, bio);
+ }
+#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
- if(!SSL_set_fd(backend->handle, (int)sockfd)) {
+ if(!SSL_set_fd(backend->handle, (int)cf->conn->sock[cf->sockindex])) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
+#endif /* !USE_BIO_CHAIN */
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
@@ -593,25 +719,23 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
static CURLcode
-wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const char * const dispname = SSL_HOST_DISPNAME();
- const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
DEBUGASSERT(backend);
ERR_clear_error();
- conn->recv[sockindex] = wolfssl_recv;
- conn->send[sockindex] = wolfssl_send;
-
/* Enable RFC2818 checks */
- if(SSL_CONN_CONFIG(verifyhost)) {
- char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ if(conn_config->verifyhost) {
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, NULL);
if(!snihost ||
(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
return CURLE_SSL_CONNECT_ERROR;
@@ -661,32 +785,32 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
failf(data, " subject alt name(s) or common name do not match \"%s\"",
- dispname);
+ connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
#else
/* When the wolfssl_check_domain_name() is used and you desire to
- * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
+ * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
* == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
* error. The only way to do this is currently to switch the
* Wolfssl_check_domain_name() in and out based on the
- * 'conn->ssl_config.verifyhost' value. */
- if(SSL_CONN_CONFIG(verifyhost)) {
+ * 'ssl_config.verifyhost' value. */
+ if(conn_config->verifyhost) {
failf(data,
" subject alt name(s) or common name do not match \"%s\"\n",
- dispname);
+ connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data,
" subject alt name(s) and/or common name do not match \"%s\"",
- dispname);
+ connssl->dispname);
return CURLE_OK;
}
#endif
}
#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
else if(ASN_NO_SIGNER_E == detail) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(conn_config->verifypeer) {
failf(data, " CA signer not available for verification");
return CURLE_SSL_CACERT_BADFILE;
}
@@ -751,7 +875,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAVE_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int rc;
char *protocol = NULL;
unsigned short protocol_len = 0;
@@ -763,17 +887,17 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
#ifdef USE_HTTP2
else if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
protocol_len == ALPN_H2_LENGTH &&
!memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH))
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
#endif
else
infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
protocol);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else if(rc == SSL_ALPN_NOT_FOUND)
@@ -799,28 +923,26 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
static CURLcode
-wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *old_ssl_sessionid = NULL;
/* SSL_get1_session allocates memory that has to be freed. */
SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle);
- bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
if(our_ssl_sessionid) {
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
- &old_ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing");
@@ -830,8 +952,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex, NULL);
+ result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
SSL_SESSION_free(our_ssl_sessionid);
@@ -857,14 +978,13 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
-static ssize_t wolfssl_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t wolfssl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
@@ -896,10 +1016,9 @@ static ssize_t wolfssl_send(struct Curl_easy *data,
return rc;
}
-static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void) data;
@@ -921,14 +1040,13 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
}
}
-static ssize_t wolfssl_recv(struct Curl_easy *data,
- int num,
+static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
char *buf,
size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
@@ -983,15 +1101,20 @@ static size_t wolfssl_version(char *buffer, size_t size)
static int wolfssl_init(void)
{
+ int ret;
+
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_open();
#endif
- return (wolfSSL_Init() == SSL_SUCCESS);
+ ret = (wolfSSL_Init() == SSL_SUCCESS);
+ bio_cf_init_methods();
+ return ret;
}
static void wolfssl_cleanup(void)
{
+ bio_cf_free_methods();
wolfSSL_Cleanup();
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_close();
@@ -999,14 +1122,15 @@ static void wolfssl_cleanup(void)
}
-static bool wolfssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool wolfssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- if(backend->handle) /* SSL is in use */
- return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->handle) /* SSL is in use */
+ return (0 != SSL_pending(ctx->backend->handle)) ? TRUE : FALSE;
else
return FALSE;
}
@@ -1016,36 +1140,33 @@ static bool wolfssl_data_pending(const struct connectdata *conn,
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int wolfssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *ctx = cf->ctx;
int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- (void) data;
-
- DEBUGASSERT(backend);
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
- if(backend->handle) {
+ if(ctx->backend->handle) {
ERR_clear_error();
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(ctx->backend->handle);
+ ctx->backend->handle = NULL;
}
return retval;
}
static CURLcode
-wolfssl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
+wolfssl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool nonblocking,
+ bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -1064,7 +1185,7 @@ wolfssl_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = wolfssl_connect_step1(data, conn, sockindex);
+ result = wolfssl_connect_step1(cf, data);
if(result)
return result;
}
@@ -1119,7 +1240,7 @@ wolfssl_connect_common(struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- result = wolfssl_connect_step2(data, conn, sockindex);
+ result = wolfssl_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1128,15 +1249,13 @@ wolfssl_connect_common(struct Curl_easy *data,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = wolfssl_connect_step3(data, conn, sockindex);
+ result = wolfssl_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = wolfssl_recv;
- conn->send[sockindex] = wolfssl_send;
*done = TRUE;
}
else
@@ -1149,21 +1268,21 @@ wolfssl_connect_common(struct Curl_easy *data,
}
-static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return wolfssl_connect_common(data, conn, sockindex, TRUE, done);
+ return wolfssl_connect_common(cf, data, TRUE, done);
}
-static CURLcode wolfssl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done);
+ result = wolfssl_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1216,6 +1335,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#ifdef KEEP_PEER_CERT
SSLSUPP_PINNEDPUBKEY |
#endif
+#ifdef USE_BIO_CHAIN
+ SSLSUPP_HTTPS_PROXY |
+#endif
SSLSUPP_SSL_CTX,
sizeof(struct ssl_backend_data),
@@ -1230,7 +1352,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_cert_status_request, /* cert_status_request */
wolfssl_connect, /* connect */
wolfssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1241,7 +1363,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_false_start, /* false_start */
wolfssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ wolfssl_recv, /* recv decrypted data */
+ wolfssl_send, /* send data to encrypt */
};
#endif
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index 0cfcbe8..4c1c9a8 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -182,7 +182,7 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
const char *beg, const char *end)
{
unsigned char b;
- unsigned long len;
+ size_t len;
struct Curl_asn1Element lelem;
/* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
@@ -307,7 +307,7 @@ static const char *bit2str(const char *beg, const char *end)
*/
static const char *int2str(const char *beg, const char *end)
{
- unsigned long val = 0;
+ unsigned int val = 0;
size_t n = end - beg;
if(!n)
@@ -323,7 +323,7 @@ static const char *int2str(const char *beg, const char *end)
do
val = (val << 8) | *(const unsigned char *) beg++;
while(beg < end);
- return curl_maprintf("%s%lx", val >= 10? "0x": "", val);
+ return curl_maprintf("%s%x", val >= 10? "0x": "", val);
}
/*
@@ -953,8 +953,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
* ECC public key is all the data, a value of type BIT STRING mapped to
* OCTET STRING and should not be parsed as an ASN.1 value.
*/
- const unsigned long len =
- (unsigned long)((pubkey->end - pubkey->beg - 2) * 4);
+ const size_t len = ((pubkey->end - pubkey->beg - 2) * 4);
if(!certnum)
infof(data, " ECC Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
@@ -972,7 +971,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
if(strcasecompare(algo, "rsaEncryption")) {
const char *q;
- unsigned long len;
+ size_t len;
p = getASN1Element(&elem, pk.beg, pk.end);
if(!p)
@@ -981,7 +980,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
/* Compute key length. */
for(q = elem.beg; !*q && q < elem.end; q++)
;
- len = (unsigned long)((elem.end - q) * 8);
+ len = ((elem.end - q) * 8);
if(len) {
unsigned int i;
for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
@@ -1073,7 +1072,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
size_t cl1;
char *cp2;
CURLcode result = CURLE_OK;
- unsigned long version;
+ unsigned int version;
size_t i;
size_t j;
@@ -1276,9 +1275,12 @@ static const char *checkOID(const char *beg, const char *end,
return matched? ccp: NULL;
}
-CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *beg, const char *end)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_X509certificate cert;
struct Curl_asn1Element dn;
struct Curl_asn1Element elem;
@@ -1290,9 +1292,8 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int matched = -1;
size_t addrlen = (size_t) -1;
ssize_t len;
- const char * const hostname = SSL_HOST_NAME();
- const char * const dispname = SSL_HOST_DISPNAME();
- size_t hostlen = strlen(hostname);
+ size_t hostlen;
+
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1302,19 +1303,21 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* Verify that connection server matches info in X509 certificate at
`beg'..`end'. */
- if(!SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifyhost)
return CURLE_OK;
if(Curl_parseX509(&cert, beg, end))
return CURLE_PEER_FAILED_VERIFICATION;
+ hostlen = strlen(connssl->hostname);
+
/* Get the server IP address. */
#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
+ if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
addrlen = sizeof(struct in6_addr);
else
#endif
- if(Curl_inet_pton(AF_INET, hostname, &addr))
+ if(Curl_inet_pton(AF_INET, connssl->hostname, &addr))
addrlen = sizeof(struct in_addr);
/* Process extensions. */
@@ -1345,19 +1348,20 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
break;
switch(name.tag) {
case 2: /* DNS name. */
+ matched = 0;
len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
name.beg, name.end);
- if(len > 0 && (size_t)len == strlen(dnsname))
- matched = Curl_cert_hostcheck(dnsname,
- (size_t)len, hostname, hostlen);
- else
- matched = 0;
- free(dnsname);
+ if(len > 0) {
+ if(size_t)len == strlen(dnsname)
+ matched = Curl_cert_hostcheck(dnsname, (size_t)len,
+ connssl->hostname, hostlen);
+ free(dnsname);
+ }
break;
case 7: /* IP address. */
- matched = (size_t) (name.end - name.beg) == addrlen &&
- !memcmp(&addr, name.beg, addrlen);
+ matched = (name.end - name.beg) == addrlen &&
+ !memcmp(&addr, name.beg, addrlen);
break;
}
}
@@ -1367,12 +1371,12 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
switch(matched) {
case 1:
/* an alternative name matched the server hostname */
- infof(data, " subjectAltName: %s matched", dispname);
+ infof(data, " subjectAltName: %s matched", connssl->dispname);
return CURLE_OK;
case 0:
/* an alternative name field existed, but didn't match and then
we MUST fail */
- infof(data, " subjectAltName does not match %s", dispname);
+ infof(data, " subjectAltName does not match %s", connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1402,21 +1406,19 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
failf(data, "SSL: unable to obtain common name from peer certificate");
else {
len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
- if(len < 0) {
- free(dnsname);
+ if(len < 0)
return CURLE_OUT_OF_MEMORY;
- }
if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
failf(data, "SSL: illegal cert name field");
else if(Curl_cert_hostcheck((const char *) dnsname,
- len, hostname, hostlen)) {
+ len, connssl->hostname, hostlen)) {
infof(data, " common name: %s (matched)", dnsname);
free(dnsname);
return CURLE_OK;
}
else
failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", dnsname, dispname);
+ "target host name '%s'", dnsname, connssl->dispname);
free(dnsname);
}
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.h b/Utilities/cmcurl/lib/vtls/x509asn1.h
index a18fa11..eb8e959 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.h
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.h
@@ -30,6 +30,7 @@
#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#include "cfilters.h"
#include "urldata.h"
/*
@@ -73,7 +74,7 @@ int Curl_parseX509(struct Curl_X509certificate *cert,
const char *beg, const char *end);
CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
const char *beg, const char *end);
-CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
const char *beg, const char *end);
#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
* or USE_SECTRANSP */
diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c
index a673446..c1b2622 100644
--- a/Utilities/cmcurl/lib/ws.c
+++ b/Utilities/cmcurl/lib/ws.c
@@ -172,10 +172,9 @@ CURLcode Curl_ws_accept(struct Curl_easy *data)
/* remove the spent bytes from the beginning of the buffer as that part has
now been delivered to the application */
-static void ws_decode_clear(struct Curl_easy *data)
+static void ws_decode_shift(struct Curl_easy *data, size_t spent)
{
struct websocket *wsp = &data->req.p.http->ws;
- size_t spent = wsp->usedbuf;
size_t len = Curl_dyn_len(&wsp->buf);
size_t keep = len - spent;
DEBUGASSERT(len >= spent);
@@ -198,42 +197,27 @@ static void ws_decode_clear(struct Curl_easy *data)
*/
static CURLcode ws_decode(struct Curl_easy *data,
- unsigned char *wpkt, size_t ilen,
- unsigned char **out, size_t *olen,
+ unsigned char *inbuf, size_t inlen,
+ size_t *headlen, size_t *olen,
curl_off_t *oleft,
- bool *more,
unsigned int *flags)
{
bool fin;
unsigned char opcode;
curl_off_t total;
size_t dataindex = 2;
- curl_off_t plen; /* size of data in the buffer */
curl_off_t payloadsize;
- struct websocket *wsp = &data->req.p.http->ws;
- unsigned char *p;
- CURLcode result;
- *olen = 0;
+ *olen = *headlen = 0;
- /* add the incoming bytes, if any */
- if(wpkt) {
- result = Curl_dyn_addn(&wsp->buf, wpkt, ilen);
- if(result)
- return result;
- }
-
- plen = Curl_dyn_len(&wsp->buf);
- if(plen < 2) {
+ if(inlen < 2) {
/* the smallest possible frame is two bytes */
- infof(data, "WS: plen == %u, EAGAIN", (int)plen);
+ infof(data, "WS: plen == %u, EAGAIN", (int)inlen);
return CURLE_AGAIN;
}
- p = Curl_dyn_uptr(&wsp->buf);
-
- fin = p[0] & WSBIT_FIN;
- opcode = p[0] & WSBIT_OPCODE_MASK;
+ fin = inbuf[0] & WSBIT_FIN;
+ opcode = inbuf[0] & WSBIT_OPCODE_MASK;
infof(data, "WS:%d received FIN bit %u", __LINE__, (int)fin);
*flags = 0;
switch(opcode) {
@@ -264,62 +248,56 @@ static CURLcode ws_decode(struct Curl_easy *data,
break;
}
- if(p[1] & WSBIT_MASK) {
+ if(inbuf[1] & WSBIT_MASK) {
/* A client MUST close a connection if it detects a masked frame. */
failf(data, "WS: masked input frame");
return CURLE_RECV_ERROR;
}
- payloadsize = p[1];
+ payloadsize = inbuf[1];
if(payloadsize == 126) {
- if(plen < 4) {
- infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)plen);
+ if(inlen < 4) {
+ infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)inlen);
return CURLE_AGAIN; /* not enough data available */
}
- payloadsize = (p[2] << 8) | p[3];
+ payloadsize = (inbuf[2] << 8) | inbuf[3];
dataindex += 2;
}
else if(payloadsize == 127) {
/* 64 bit payload size */
- if(plen < 10)
+ if(inlen < 10)
return CURLE_AGAIN;
- if(p[2] & 80) {
+ if(inbuf[2] & 80) {
failf(data, "WS: too large frame");
return CURLE_RECV_ERROR;
}
dataindex += 8;
- payloadsize = ((curl_off_t)p[2] << 56) |
- (curl_off_t)p[3] << 48 |
- (curl_off_t)p[4] << 40 |
- (curl_off_t)p[5] << 32 |
- (curl_off_t)p[6] << 24 |
- (curl_off_t)p[7] << 16 |
- (curl_off_t)p[8] << 8 |
- p[9];
+ payloadsize = ((curl_off_t)inbuf[2] << 56) |
+ (curl_off_t)inbuf[3] << 48 |
+ (curl_off_t)inbuf[4] << 40 |
+ (curl_off_t)inbuf[5] << 32 |
+ (curl_off_t)inbuf[6] << 24 |
+ (curl_off_t)inbuf[7] << 16 |
+ (curl_off_t)inbuf[8] << 8 |
+ inbuf[9];
}
+ /* point to the payload */
+ *headlen = dataindex;
total = dataindex + payloadsize;
- if(total > plen) {
- /* deliver a partial frame */
- *oleft = total - dataindex;
+ if(total > (curl_off_t)inlen) {
+ /* buffer contains partial frame */
+ *olen = inlen - dataindex; /* bytes to write out */
+ *oleft = total - inlen; /* bytes yet to come (for this frame) */
payloadsize = total - dataindex;
}
else {
- *oleft = 0;
- if(plen > total)
- /* there is another fragment after */
- *more = TRUE;
+ /* we have the complete frame (`total` bytes) in buffer */
+ *olen = payloadsize; /* bytes to write out */
+ *oleft = 0; /* bytes yet to come (for this frame) */
}
- /* point to the payload */
- *out = &p[dataindex];
-
- /* return the payload length */
- *olen = payloadsize;
-
- /* number of bytes "used" from the buffer */
- wsp->usedbuf = dataindex + payloadsize;
- infof(data, "WS: received %zu bytes payload (%zu left)",
- payloadsize, *oleft);
+ infof(data, "WS: received %zu bytes payload (%zu left, buflen was %zu)",
+ payloadsize, *oleft, inlen);
return CURLE_OK;
}
@@ -332,76 +310,83 @@ size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */,
{
struct HTTP *ws = (struct HTTP *)userp;
struct Curl_easy *data = ws->ws.data;
+ struct websocket *wsp = &data->req.p.http->ws;
void *writebody_ptr = data->set.out;
if(data->set.ws_raw_mode)
return data->set.fwrite_func(buffer, size, nitems, writebody_ptr);
else if(nitems) {
- unsigned char *frame = NULL;
- size_t flen = 0;
- size_t wrote = 0;
+ size_t wrote = 0, headlen;
CURLcode result;
- bool more; /* there's is more to parse in the buffer */
- curl_off_t oleft;
-
- decode:
- more = FALSE;
- oleft = ws->ws.frame.bytesleft;
- if(!oleft) {
- unsigned int recvflags;
- result = ws_decode(data, (unsigned char *)buffer, nitems,
- &frame, &flen, &oleft, &more, &recvflags);
- if(result == CURLE_AGAIN)
- /* insufficient amount of data, keep it for later */
- return nitems;
- else if(result) {
- infof(data, "WS: decode error %d", (int)result);
+
+ if(buffer) {
+ result = Curl_dyn_addn(&wsp->buf, buffer, nitems);
+ if(result) {
+ infof(data, "WS: error adding data to buffer %d", (int)result);
return nitems - 1;
}
- /* Store details about the frame to be reachable with curl_ws_meta()
- from within the write callback */
- ws->ws.frame.age = 0;
- ws->ws.frame.offset = 0;
- ws->ws.frame.flags = recvflags;
- ws->ws.frame.bytesleft = oleft;
+ buffer = NULL;
}
- else {
- if(nitems > (size_t)ws->ws.frame.bytesleft) {
- nitems = ws->ws.frame.bytesleft;
- more = TRUE;
+
+ while(Curl_dyn_len(&wsp->buf)) {
+ unsigned char *wsbuf = Curl_dyn_uptr(&wsp->buf);
+ size_t buflen = Curl_dyn_len(&wsp->buf);
+ size_t write_len = 0;
+ size_t consumed = 0;
+
+ if(!ws->ws.frame.bytesleft) {
+ unsigned int recvflags;
+ curl_off_t fb_left;
+
+ result = ws_decode(data, wsbuf, buflen,
+ &headlen, &write_len, &fb_left, &recvflags);
+ consumed += headlen;
+ wsbuf += headlen;
+ buflen -= headlen;
+ if(result == CURLE_AGAIN)
+ /* insufficient amount of data, keep it for later.
+ * we pretend to have written all since we have a copy */
+ return nitems;
+ else if(result) {
+ infof(data, "WS: decode error %d", (int)result);
+ return nitems - 1;
+ }
+ /* New frame. store details about the frame to be reachable with
+ curl_ws_meta() from within the write callback */
+ ws->ws.frame.age = 0;
+ ws->ws.frame.offset = 0;
+ ws->ws.frame.flags = recvflags;
+ ws->ws.frame.bytesleft = fb_left;
}
- else
- more = FALSE;
- ws->ws.frame.offset += nitems;
- ws->ws.frame.bytesleft -= nitems;
- frame = (unsigned char *)buffer;
- flen = nitems;
- }
- if((ws->ws.frame.flags & CURLWS_PING) && !oleft) {
- /* auto-respond to PINGs, only works for single-frame payloads atm */
- size_t bytes;
- infof(data, "WS: auto-respond to PING with a PONG");
- DEBUGASSERT(frame);
- /* send back the exact same content as a PONG */
- result = curl_ws_send(data, frame, flen, &bytes, 0, CURLWS_PONG);
- if(result)
- return result;
- }
- else {
- /* deliver the decoded frame to the user callback */
- Curl_set_in_callback(data, true);
- wrote = data->set.fwrite_func((char *)frame, 1, flen, writebody_ptr);
- Curl_set_in_callback(data, false);
- if(wrote != flen)
- return 0;
- }
- if(oleft)
- ws->ws.frame.offset += flen;
- /* the websocket frame has been delivered */
- ws_decode_clear(data);
- if(more) {
- /* there's more websocket data to deal with in the buffer */
- buffer = NULL; /* the buffer as been drained already */
- goto decode;
+ else {
+ /* continuing frame */
+ write_len = (size_t)ws->ws.frame.bytesleft;
+ if(write_len > buflen)
+ write_len = buflen;
+ ws->ws.frame.offset += write_len;
+ ws->ws.frame.bytesleft -= write_len;
+ }
+ if((ws->ws.frame.flags & CURLWS_PING) && !ws->ws.frame.bytesleft) {
+ /* auto-respond to PINGs, only works for single-frame payloads atm */
+ size_t bytes;
+ infof(data, "WS: auto-respond to PING with a PONG");
+ /* send back the exact same content as a PONG */
+ result = curl_ws_send(data, wsbuf, write_len,
+ &bytes, 0, CURLWS_PONG);
+ if(result)
+ return result;
+ }
+ else if(write_len || !wsp->frame.bytesleft) {
+ /* deliver the decoded frame to the user callback */
+ Curl_set_in_callback(data, true);
+ wrote = data->set.fwrite_func((char *)wsbuf, 1,
+ write_len, writebody_ptr);
+ Curl_set_in_callback(data, false);
+ if(wrote != write_len)
+ return 0;
+ }
+ /* get rid of the buffered data consumed */
+ consumed += write_len;
+ ws_decode_shift(data, consumed);
}
}
return nitems;
@@ -412,9 +397,9 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
size_t buflen, size_t *nread,
struct curl_ws_frame **metap)
{
- size_t bytes;
CURLcode result;
struct websocket *wsp = &data->req.p.http->ws;
+ bool done = FALSE; /* not filled passed buffer yet */
*nread = 0;
*metap = NULL;
@@ -423,84 +408,81 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
if(result)
return result;
- do {
- bool drain = FALSE; /* if there is pending buffered data to drain */
- char *inbuf = data->state.buffer;
- bytes = wsp->stillbuffer;
- if(!bytes) {
+ while(!done) {
+ size_t write_len;
+ unsigned int recvflags;
+
+ if(!wsp->stillblen) {
+ /* try to get more data */
+ size_t n;
result = curl_easy_recv(data, data->state.buffer,
- data->set.buffer_size, &bytes);
+ data->set.buffer_size, &n);
if(result)
return result;
+ if(!n)
+ /* connection closed */
+ return CURLE_GOT_NOTHING;
+ wsp->stillb = data->state.buffer;
+ wsp->stillblen = n;
+ }
+
+ infof(data, "WS: got %u websocket bytes to decode",
+ (int)wsp->stillblen);
+ if(!wsp->frame.bytesleft) {
+ size_t headlen;
+ curl_off_t oleft;
+ /* detect new frame */
+ result = ws_decode(data, (unsigned char *)wsp->stillb, wsp->stillblen,
+ &headlen, &write_len, &oleft, &recvflags);
+ if(result == CURLE_AGAIN)
+ /* a packet fragment only */
+ break;
+ else if(result)
+ return result;
+ wsp->stillb += headlen;
+ wsp->stillblen -= headlen;
+ wsp->frame.offset = 0;
+ wsp->frame.bytesleft = oleft;
+ wsp->frame.flags = recvflags;
}
else {
- /* the pending bytes can be found here */
- inbuf = wsp->stillb;
- drain = TRUE;
+ /* existing frame, remaining payload handling */
+ write_len = wsp->frame.bytesleft;
+ if(write_len > wsp->stillblen)
+ write_len = wsp->stillblen;
}
- if(bytes) {
- unsigned char *out;
- size_t olen;
- bool more;
- unsigned int recvflags;
- curl_off_t oleft = wsp->frame.bytesleft;
-
- infof(data, "WS: got %u websocket bytes to decode", (int)bytes);
- if(!oleft && !drain) {
- result = ws_decode(data, (unsigned char *)inbuf, bytes,
- &out, &olen, &oleft, &more, &recvflags);
- if(result == CURLE_AGAIN)
- /* a packet fragment only */
- break;
- else if(result)
- return result;
- wsp->frame.offset = 0;
- wsp->frame.bytesleft = oleft;
- wsp->frame.flags = recvflags;
- }
- else {
- olen = oleft;
- out = (unsigned char *)wsp->stillb;
- recvflags = wsp->frame.flags;
- if((curl_off_t)buflen < oleft)
- /* there is still data left after this */
- wsp->frame.bytesleft -= buflen;
- else
- wsp->frame.bytesleft = 0;
- }
- /* auto-respond to PINGs */
- if((recvflags & CURLWS_PING) && !oleft) {
- infof(data, "WS: auto-respond to PING with a PONG");
- /* send back the exact same content as a PONG */
- result = curl_ws_send(data, out, olen, &bytes, 0, CURLWS_PONG);
- if(result)
- return result;
- }
- else {
- if(olen < buflen) {
- /* copy the payload to the user buffer */
- memcpy(buffer, out, olen);
- *nread = olen;
- if(!oleft)
- /* websocket frame has been delivered */
- ws_decode_clear(data);
- }
- else {
- /* copy a partial payload */
- memcpy(buffer, out, buflen);
- *nread = buflen;
- /* remember what is left and where */
- wsp->stillbuffer = olen - buflen;
- wsp->stillb = (char *)buffer + buflen;
- }
- wsp->frame.offset += *nread;
- }
+ /* auto-respond to PINGs */
+ if((wsp->frame.flags & CURLWS_PING) && !wsp->frame.bytesleft) {
+ infof(data, "WS: auto-respond to PING with a PONG");
+ /* send back the exact same content as a PONG */
+ result = curl_ws_send(data, wsp->stillb, write_len,
+ &write_len, 0, CURLWS_PONG);
+ if(result)
+ return result;
}
- else
- *nread = bytes;
- break;
- } while(1);
+ else if(write_len || !wsp->frame.bytesleft) {
+ if(write_len > buflen)
+ write_len = buflen;
+ /* copy the payload to the user buffer */
+ memcpy(buffer, wsp->stillb, write_len);
+ *nread = write_len;
+ done = TRUE;
+ }
+ if(write_len) {
+ /* update buffer and frame info */
+ wsp->frame.offset += write_len;
+ DEBUGASSERT(wsp->frame.bytesleft >= (curl_off_t)write_len);
+ if(wsp->frame.bytesleft)
+ wsp->frame.bytesleft -= write_len;
+ DEBUGASSERT(write_len <= wsp->stillblen);
+ wsp->stillblen -= write_len;
+ if(wsp->stillblen)
+ wsp->stillb += write_len;
+ else
+ wsp->stillb = NULL;
+ }
+ }
*metap = &wsp->frame;
return CURLE_OK;
}
@@ -649,9 +631,14 @@ CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
return CURLE_OK;
/* raw mode sends exactly what was requested, and this is from within
the write callback */
- if(Curl_is_in_callback(data))
+ if(Curl_is_in_callback(data)) {
+ if(!data->conn) {
+ failf(data, "No associated connection");
+ return CURLE_SEND_ERROR;
+ }
result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
&written);
+ }
else
result = Curl_senddata(data, buffer, buflen, &written);
@@ -732,7 +719,7 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
(void)buflen;
(void)nread;
(void)metap;
- return CURLE_OK;
+ return CURLE_NOT_BUILT_IN;
}
CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
@@ -746,7 +733,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
(void)sent;
(void)framesize;
(void)sendflags;
- return CURLE_OK;
+ return CURLE_NOT_BUILT_IN;
}
CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
diff --git a/Utilities/cmcurl/lib/ws.h b/Utilities/cmcurl/lib/ws.h
index 341242e..2f3ed2d 100644
--- a/Utilities/cmcurl/lib/ws.h
+++ b/Utilities/cmcurl/lib/ws.h
@@ -48,9 +48,9 @@ struct websocket {
struct curl_ws_frame frame; /* the struct used for frame state */
curl_off_t oleft; /* outstanding number of payload bytes left from the
server */
- curl_off_t stillbuffer; /* number of bytes left in the buffer to deliver in
- the next curl_ws_recv() call */
- char *stillb; /* the stillbuffer pending bytes are here */
+ size_t stillblen; /* number of bytes left in the buffer to deliver in
+ the next curl_ws_recv() call */
+ char *stillb; /* the stillblen pending bytes are here */
curl_off_t sleft; /* outstanding number of payload bytes left to send */
unsigned int xori; /* xor index */
};
diff --git a/Utilities/cmnghttp2/CMakeLists.txt b/Utilities/cmnghttp2/CMakeLists.txt
index 9002ab6..6d0c76f 100644
--- a/Utilities/cmnghttp2/CMakeLists.txt
+++ b/Utilities/cmnghttp2/CMakeLists.txt
@@ -19,6 +19,7 @@ add_library(cmnghttp2 STATIC
lib/nghttp2_buf.c
lib/nghttp2_callbacks.c
lib/nghttp2_debug.c
+ lib/nghttp2_extpri.c
lib/nghttp2_frame.c
lib/nghttp2_hd.c
lib/nghttp2_hd_huffman.c
diff --git a/Utilities/cmnghttp2/cmakeconfig.h.in b/Utilities/cmnghttp2/cmakeconfig.h.in
index 60698fb..8b14df2 100644
--- a/Utilities/cmnghttp2/cmakeconfig.h.in
+++ b/Utilities/cmnghttp2/cmakeconfig.h.in
@@ -8,9 +8,6 @@
/* Define to `int' if <sys/types.h> does not define. */
#cmakedefine ssize_t @ssize_t@
-/* sizeof(int *) */
-#define SIZEOF_INT_P KWIML_ABI_SIZEOF_DATA_PTR
-
/* Define to 1 if you have the <arpa/inet.h> header file. */
#cmakedefine HAVE_ARPA_INET_H 1
diff --git a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
index e3aeb9f..65077dd 100644
--- a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
+++ b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
@@ -229,6 +229,13 @@ typedef struct {
#define NGHTTP2_CLIENT_MAGIC_LEN 24
/**
+ * @macro
+ *
+ * The default max number of settings per SETTINGS frame
+ */
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
+
+/**
* @enum
*
* Error codes used in this library. The code range is [-999, -500],
@@ -399,12 +406,17 @@ typedef enum {
*/
NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
/**
- * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
- * under unexpected condition and processing was terminated (e.g.,
- * out of memory). If application receives this error code, it must
- * stop using that :type:`nghttp2_session` object and only allowed
- * operation for that object is deallocate it using
- * `nghttp2_session_del()`.
+ * When a local endpoint receives too many settings entries
+ * in a single SETTINGS frame.
+ */
+ NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
+ /**
+ * The errors < :enum:`nghttp2_error.NGHTTP2_ERR_FATAL` mean that
+ * the library is under unexpected condition and processing was
+ * terminated (e.g., out of memory). If application receives this
+ * error code, it must stop using that :type:`nghttp2_session`
+ * object and only allowed operation for that object is deallocate
+ * it using `nghttp2_session_del()`.
*/
NGHTTP2_ERR_FATAL = -900,
/**
@@ -533,9 +545,9 @@ typedef struct {
* :type:`nghttp2_on_frame_send_callback`, and
* :type:`nghttp2_on_frame_not_send_callback`), it may not be
* NULL-terminated if header field is passed from application with
- * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`). When application
- * is constructing this struct, |name| is not required to be
- * NULL-terminated.
+ * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`).
+ * When application is constructing this struct, |name| is not
+ * required to be NULL-terminated.
*/
uint8_t *name;
/**
@@ -546,9 +558,9 @@ typedef struct {
* :type:`nghttp2_on_frame_send_callback`, and
* :type:`nghttp2_on_frame_not_send_callback`), it may not be
* NULL-terminated if header field is passed from application with
- * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`). When
- * application is constructing this struct, |value| is not required
- * to be NULL-terminated.
+ * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE`).
+ * When application is constructing this struct, |value| is not
+ * required to be NULL-terminated.
*/
uint8_t *value;
/**
@@ -622,7 +634,11 @@ typedef enum {
* The ORIGIN frame, which is defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*/
- NGHTTP2_ORIGIN = 0x0c
+ NGHTTP2_ORIGIN = 0x0c,
+ /**
+ * The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`.
+ */
+ NGHTTP2_PRIORITY_UPDATE = 0x10
} nghttp2_frame_type;
/**
@@ -691,7 +707,11 @@ typedef enum {
* SETTINGS_ENABLE_CONNECT_PROTOCOL
* (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
*/
- NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
+ NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
+ /**
+ * SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`)
+ */
+ NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
} nghttp2_settings_id;
/* Note: If we add SETTINGS, update the capacity of
NGHTTP2_INBOUND_NUM_IV as well */
@@ -705,8 +725,8 @@ typedef enum {
*
* Default maximum number of incoming concurrent streams. Use
* `nghttp2_submit_settings()` with
- * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
- * maximum number of incoming concurrent streams.
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS`
+ * to change the maximum number of incoming concurrent streams.
*
* .. note::
*
@@ -860,38 +880,41 @@ typedef enum {
* The implementation of this function must read at most |length|
* bytes of data from |source| (or possibly other places) and store
* them in |buf| and return number of data stored in |buf|. If EOF is
- * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|.
+ * reached, set :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag
+ * in |*data_flags|.
*
* Sometime it is desirable to avoid copying data into |buf| and let
* application to send data directly. To achieve this, set
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly
- * other flags, just like when we do copy), and return the number of
- * bytes to send without copying data into |buf|. The library, seeing
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` to
+ * |*data_flags| (and possibly other flags, just like when we do
+ * copy), and return the number of bytes to send without copying data
+ * into |buf|. The library, seeing
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
* :type:`nghttp2_send_data_callback`. The application must send
* complete DATA frame in that callback.
*
* If this callback is set by `nghttp2_submit_request()`,
* `nghttp2_submit_response()` or `nghttp2_submit_headers()` and
* `nghttp2_submit_data()` with flag parameter
- * :enum:`NGHTTP2_FLAG_END_STREAM` set, and
- * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA
- * frame will have END_STREAM flag set. Usually, this is expected
- * behaviour and all are fine. One exception is send trailer fields.
- * You cannot send trailer fields after sending frame with END_STREAM
- * set. To avoid this problem, one can set
- * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with
- * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set
- * END_STREAM in DATA frame. Then application can use
- * `nghttp2_submit_trailer()` to send trailer fields.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag is set to
+ * |*data_flags|, DATA frame will have END_STREAM flag set. Usually,
+ * this is expected behaviour and all are fine. One exception is send
+ * trailer fields. You cannot send trailer fields after sending frame
+ * with END_STREAM set. To avoid this problem, one can set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along
+ * with :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` to signal the
+ * library not to set END_STREAM in DATA frame. Then application can
+ * use `nghttp2_submit_trailer()` to send trailer fields.
* `nghttp2_submit_trailer()` can be called inside this callback.
*
* If the application wants to postpone DATA frames (e.g.,
* asynchronous I/O, or reading data blocks for long time), it is
- * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
- * any data in this invocation. The library removes DATA frame from
- * the outgoing queue temporarily. To move back deferred DATA frame
- * to outgoing queue, call `nghttp2_session_resume_data()`.
+ * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED`
+ * without reading any data in this invocation. The library removes
+ * DATA frame from the outgoing queue temporarily. To move back
+ * deferred DATA frame to outgoing queue, call
+ * `nghttp2_session_resume_data()`.
*
* By default, |length| is limited to 16KiB at maximum. If peer
* allows larger frames, application can enlarge transmission buffer
@@ -900,16 +923,17 @@ typedef enum {
*
* If the application just wants to return from
* `nghttp2_session_send()` or `nghttp2_session_mem_send()` without
- * sending anything, return :enum:`NGHTTP2_ERR_PAUSE`.
+ * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`.
*
* In case of error, there are 2 choices. Returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
- * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a
- * different error code is desirable, use
- * `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream by issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. If a different
+ * error code is desirable, use `nghttp2_submit_rst_stream()` with a
+ * desired error code and then return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will
+ * signal the entire session failure.
*/
typedef ssize_t (*nghttp2_data_source_read_callback)(
nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
@@ -1289,8 +1313,9 @@ typedef union {
* |length| bytes of data stored in |data|. The |flags| is currently
* not used and always 0. It must return the number of bytes sent if
* it succeeds. If it cannot send any single byte without blocking,
- * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`. For other errors,
- * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The
+ * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. For
+ * other errors, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The
* |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
@@ -1318,9 +1343,10 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
/**
* @functypedef
*
- * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
- * used in :type:`nghttp2_data_source_read_callback` to send complete
- * DATA frame.
+ * Callback function invoked when
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :type:`nghttp2_data_source_read_callback` to send complete DATA
+ * frame.
*
* The |frame| is a DATA frame to send. The |framehd| is the
* serialized frame header (9 bytes). The |length| is the length of
@@ -1338,21 +1364,22 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
* If all data were written successfully, return 0.
*
* If it cannot send any data at all, just return
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback
- * with the same parameters later (It is recommended to send complete
- * DATA frame at once in this function to deal with error; if partial
- * frame data has already sent, it is impossible to send another data
- * in that state, and all we can do is tear down connection). When
- * data is fully processed, but application wants to make
- * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return
- * immediately without processing next frames, return
- * :enum:`NGHTTP2_ERR_PAUSE`. If application decided to reset this
- * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`; the library will call
+ * this callback with the same parameters later (It is recommended to
+ * send complete DATA frame at once in this function to deal with
+ * error; if partial frame data has already sent, it is impossible to
+ * send another data in that state, and all we can do is tear down
+ * connection). When data is fully processed, but application wants
+ * to make `nghttp2_session_mem_send()` or `nghttp2_session_send()`
+ * return immediately without processing next frames, return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. If application decided to
+ * reset this stream, return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
* the library will send RST_STREAM with INTERNAL_ERROR as error code.
* The application can also return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in
- * connection closure. Returning any other value is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which will
+ * result in connection closure. Returning any other value is treated
+ * as :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
*/
typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
nghttp2_frame *frame,
@@ -1369,11 +1396,13 @@ typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
* currently not used and always 0. It must return the number of
* bytes written in |buf| if it succeeds. If it cannot read any
* single byte without blocking, it must return
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF before it reads any
- * single byte, it must return :enum:`NGHTTP2_ERR_EOF`. For other
- * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
- * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`. The
- * |user_data| pointer is the third argument passed in to the call to
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF
+ * before it reads any single byte, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`. For other errors, it must
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * Returning 0 is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. The |user_data|
+ * pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
* This callback is required if the application uses
@@ -1401,12 +1430,6 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
* respectively. The header name/value pairs are emitted via
* :type:`nghttp2_on_header_callback`.
*
- * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
- * called after stream is closed (see
- * :type:`nghttp2_on_stream_close_callback`). The application should
- * check that stream is still alive using its own stream management or
- * :func:`nghttp2_session_get_stream_user_data()`.
- *
* Only HEADERS and DATA frame can signal the end of incoming data.
* If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
* |frame| is the last frame from the remote peer in this stream.
@@ -1417,7 +1440,8 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
* The implementation of this function must return 0 if it succeeds.
* If nonzero value is returned, it is treated as fatal error and
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
@@ -1445,7 +1469,8 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
@@ -1468,9 +1493,9 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)(
* `nghttp2_session_server_new()`.
*
* If the application uses `nghttp2_session_mem_recv()`, it can return
- * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
- * return without processing further input bytes. The memory by
- * pointed by the |data| is retained until
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes. The memory by pointed by the |data| is retained until
* `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
* The application must retain the input bytes which was used to
* produce the |data| parameter, because it may refer to the memory
@@ -1479,7 +1504,8 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)(
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error, and
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
@@ -1499,19 +1525,20 @@ typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
* `nghttp2_session_server_new()`.
*
* The implementation of this function must return 0 if it succeeds.
- * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the
- * transmission of the given frame.
+ * It can also return :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` to
+ * cancel the transmission of the given frame.
*
* If there is a fatal error while executing this callback, the
- * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
- * which makes `nghttp2_session_send()` and
- * `nghttp2_session_mem_send()` functions immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * implementation should return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which makes
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* If the other value is returned, it is treated as if
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. But the
- * implementation should not rely on this since the library may define
- * new return value to extend its capability.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ * But the implementation should not rely on this since the library
+ * may define new return value to extend its capability.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_before_frame_send_callback()`.
@@ -1530,7 +1557,8 @@ typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session,
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_send_callback()`.
@@ -1552,7 +1580,8 @@ typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* `nghttp2_session_get_stream_user_data()` can be used to get
* associated data.
@@ -1583,7 +1612,8 @@ typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
* If nonzero is returned, it is treated as fatal error and
* `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
* `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
- * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * functions immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_stream_close_callback()`.
@@ -1601,10 +1631,11 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
* will be emitted by :type:`nghttp2_on_header_callback`.
*
* The ``frame->hd.flags`` may not have
- * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one
- * or more CONTINUATION frames are involved. But the application does
- * not need to care about that because the header name/value pairs are
- * emitted transparently regardless of CONTINUATION frames.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_HEADERS` flag set, which
+ * indicates that one or more CONTINUATION frames are involved. But
+ * the application does not need to care about that because the header
+ * name/value pairs are emitted transparently regardless of
+ * CONTINUATION frames.
*
* The server applications probably create an object to store
* information about new stream if ``frame->hd.type ==
@@ -1627,26 +1658,31 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
* trailer fields also has ``frame->headers.cat ==
* NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
*
- * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
- * the stream (promised stream if frame is PUSH_PROMISE) by issuing
- * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case,
* :type:`nghttp2_on_header_callback` and
* :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a
* different error code is desirable, use
* `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use
- * ``frame->push_promise.promised_stream_id`` as stream_id parameter
- * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Again, use ``frame->push_promise.promised_stream_id`` as stream_id
+ * parameter in `nghttp2_submit_rst_stream()` if frame is
+ * PUSH_PROMISE.
*
* The implementation of this function must return 0 if it succeeds.
- * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
+ * It can return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
* reset the stream (promised stream if frame is PUSH_PROMISE). For
* critical errors, it must return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the other value is
- * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
- * is returned. If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * value is returned, it is treated as if
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
* `nghttp2_session_mem_recv()` function will immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
@@ -1663,16 +1699,17 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* The |value| of length |valuelen| is header value. The |flags| is
* bitwise OR of one or more of :type:`nghttp2_nv_flag`.
*
- * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
- * must not index this name/value pair when forwarding it to the next
- * hop. More specifically, "Literal Header Field never Indexed"
- * representation must be used in HPACK encoding.
+ * If :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_INDEX` is set in
+ * |flags|, the receiver must not index this name/value pair when
+ * forwarding it to the next hop. More specifically, "Literal Header
+ * Field never Indexed" representation must be used in HPACK encoding.
*
* When this callback is invoked, ``frame->hd.type`` is either
- * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all
- * header name/value pairs are processed with this callback, and no
- * error has been detected, :type:`nghttp2_on_frame_recv_callback`
- * will be invoked. If there is an error in decompression,
+ * :enum:`nghttp2_frame_type.NGHTTP2_HEADERS` or
+ * :enum:`nghttp2_frame_type.NGHTTP2_PUSH_PROMISE`. After all header
+ * name/value pairs are processed with this callback, and no error has
+ * been detected, :type:`nghttp2_on_frame_recv_callback` will be
+ * invoked. If there is an error in decompression,
* :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
* invoked.
*
@@ -1690,34 +1727,39 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* explained in :ref:`http-messaging` section.
*
* If the application uses `nghttp2_session_mem_recv()`, it can return
- * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
- * return without processing further input bytes. The memory pointed
- * by |frame|, |name| and |value| parameters are retained until
- * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
- * The application must retain the input bytes which was used to
- * produce these parameters, because it may refer to the memory region
- * included in the input bytes.
- *
- * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
- * the stream (promised stream if frame is PUSH_PROMISE) by issuing
- * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes. The memory pointed by |frame|, |name| and |value|
+ * parameters are retained until `nghttp2_session_mem_recv()` or
+ * `nghttp2_session_recv()` is called. The application must retain
+ * the input bytes which was used to produce these parameters, because
+ * it may refer to the memory region included in the input bytes.
+ *
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case,
* :type:`nghttp2_on_header_callback` and
* :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a
* different error code is desirable, use
* `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use
- * ``frame->push_promise.promised_stream_id`` as stream_id parameter
- * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Again, use ``frame->push_promise.promised_stream_id`` as stream_id
+ * parameter in `nghttp2_submit_rst_stream()` if frame is
+ * PUSH_PROMISE.
*
* The implementation of this function must return 0 if it succeeds.
- * It may return :enum:`NGHTTP2_ERR_PAUSE` or
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical
- * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If
- * the other nonzero value is returned, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * It may return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For
+ * other critical failures, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * nonzero value is returned, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_header_callback()`.
@@ -1784,11 +1826,12 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
*
* With this callback, application inspects the incoming invalid
* field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
- * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_PROTOCOL_ERROR`. To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
*
* If 0 is returned, the header field is ignored, and the stream is
* not reset.
@@ -1819,11 +1862,12 @@ typedef int (*nghttp2_on_invalid_header_callback)(
*
* With this callback, application inspects the incoming invalid
* field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
- * error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_on_invalid_header_callback2)(
nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name,
@@ -1837,11 +1881,12 @@ typedef int (*nghttp2_on_invalid_header_callback2)(
* |frame|. The application must choose the total length of payload
* including padded bytes in range [frame->hd.length, max_payloadlen],
* inclusive. Choosing number not in this range will be treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
* ``frame->hd.length`` means no padding is added. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_select_padding_callback()`.
@@ -1861,16 +1906,17 @@ typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session,
* |remote_max_frame_size|)]. If a value greater than this range is
* returned than the max allow value will be used. Returning a value
* smaller than this range is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The |frame_type| is provided
- * for future extensibility and identifies the type of frame (see
- * :type:`nghttp2_frame_type`) for which to get the length for.
- * Currently supported frame types are: :enum:`NGHTTP2_DATA`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The
+ * |frame_type| is provided for future extensibility and identifies
+ * the type of frame (see :type:`nghttp2_frame_type`) for which to get
+ * the length for. Currently supported frame types are:
+ * :enum:`nghttp2_frame_type.NGHTTP2_DATA`.
*
* This callback can be used to control the length in bytes for which
* :type:`nghttp2_data_source_read_callback` is allowed to send to the
* remote endpoint. This callback is optional. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the
+ * entire session failure.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
@@ -1897,7 +1943,8 @@ typedef ssize_t (*nghttp2_data_source_read_length_callback)(
* The implementation of this function must return 0 if it succeeds.
* If nonzero value is returned, it is treated as fatal error and
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
@@ -1916,14 +1963,15 @@ typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
* The implementation of this function must return 0 if it succeeds.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_on_extension_chunk_recv_callback)(
nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
@@ -1953,14 +2001,15 @@ typedef int (*nghttp2_on_extension_chunk_recv_callback)(
* |*payload|, and do its own mechanism to process extension frames.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
void **payload,
@@ -1982,17 +2031,18 @@ typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
* bytes written into |buf| when it succeeds.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`, and
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and
* :type:`nghttp2_on_frame_not_send_callback` will be invoked.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is
- * strictly larger than |len|, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the return
+ * value is strictly larger than |len|, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
uint8_t *buf, size_t len,
@@ -2017,12 +2067,12 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
*
* Normally, application should return 0 from this callback. If fatal
* error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
*/
typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
size_t len, void *user_data);
@@ -2043,12 +2093,12 @@ typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
*
* Normally, application should return 0 from this callback. If fatal
* error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
*/
typedef int (*nghttp2_error_callback2)(nghttp2_session *session,
int lib_error_code, const char *msg,
@@ -2078,7 +2128,7 @@ typedef struct nghttp2_session_callbacks nghttp2_session_callbacks;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2275,7 +2325,7 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback(
* @function
*
* Sets callback function invoked when
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in
* :type:`nghttp2_data_source_read_callback` to avoid data copy.
*/
NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
@@ -2458,7 +2508,7 @@ typedef struct nghttp2_option nghttp2_option;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
@@ -2519,7 +2569,8 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
* If this option is not used or used with zero value, if MAGIC does
* not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
* and `nghttp2_session_mem_recv()` will return error
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal
+ * error.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
@@ -2604,8 +2655,8 @@ nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
* received. If this option is set to nonzero, the library won't send
* PING frame with ACK flag set in the response for incoming PING
* frame. The application can send PING frame with ACK flag set using
- * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
- * parameter.
+ * `nghttp2_submit_ping()` with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
+ * as flags parameter.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
int val);
@@ -2619,7 +2670,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
* `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If
* application attempts to send header fields larger than this limit,
* the transmission of the frame fails with error code
- * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FRAME_SIZE_ERROR`.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
@@ -2644,6 +2695,11 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
* This option prevents the library from retaining closed streams to
* maintain the priority tree. If this option is set to nonzero,
* applications can discard closed stream completely to save memory.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, any
+ * closed streams are not retained regardless of this option.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
int val);
@@ -2662,6 +2718,47 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
/**
* @function
*
+ * This function sets the maximum number of SETTINGS entries per
+ * SETTINGS frame that will be accepted. If more than those entries
+ * are received, the peer is considered to be misbehaving and session
+ * will be closed. The default value is 32.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
+ size_t val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, allows server to fallback to
+ * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not
+ * received from client, and server submitted
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * = 1 via `nghttp2_submit_settings()`. Most of the advanced
+ * functionality for RFC 7540 priorities are still disabled. This
+ * fallback only enables the minimal feature set of RFC 7540
+ * priorities to deal with priority signaling from client.
+ *
+ * Client session ignores this option.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option,
+ int val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, turns off RFC 9113 leading and
+ * trailing white spaces validation against HTTP field value. Some
+ * important fields, such as HTTP/2 pseudo header fields, are
+ * validated more strictly and this option does not apply to them.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
* Initializes |*session_ptr| for client use. The all members of
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
* does not store |callbacks|. The |user_data| is an arbitrary user
@@ -2677,7 +2774,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2703,7 +2800,7 @@ nghttp2_session_client_new(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2729,7 +2826,7 @@ nghttp2_session_server_new(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2755,7 +2852,7 @@ nghttp2_session_client_new2(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2781,7 +2878,7 @@ nghttp2_session_server_new2(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_client_new3(
@@ -2806,7 +2903,7 @@ NGHTTP2_EXTERN int nghttp2_session_client_new3(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_server_new3(
@@ -2828,12 +2925,14 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
*
* This function retrieves the highest prioritized frame from the
* outbound queue and sends it to the remote peer. It does this as
- * many as possible until the user callback
+ * many times as possible until the user callback
* :type:`nghttp2_send_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty.
- * This function calls several callback functions which are passed
- * when initializing the |session|. Here is the simple time chart
- * which tells when each callback is invoked:
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`, the outbound queue
+ * becomes empty or flow control is triggered (remote window size
+ * becomes depleted or maximum number of concurrent streams is
+ * reached). This function calls several callback functions which are
+ * passed when initializing the |session|. Here is the simple time
+ * chart which tells when each callback is invoked:
*
* 1. Get the next frame to send from outbound queue.
*
@@ -2851,7 +2950,7 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
*
* 6. :type:`nghttp2_before_frame_send_callback` is invoked.
*
- * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from
+ * 7. If :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` is returned from
* :type:`nghttp2_before_frame_send_callback`, the current frame
* transmission is canceled, and
* :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort
@@ -2869,9 +2968,9 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
*/
NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
@@ -2903,7 +3002,7 @@ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
* |*data_ptr| if it succeeds, or one of the following negative error
* codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*
* .. note::
@@ -2925,8 +3024,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
*
* This function receives as many frames as possible until the user
* callback :type:`nghttp2_recv_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`. This function calls several
- * callback functions which are passed when initializing the
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. This function calls
+ * several callback functions which are passed when initializing the
* |session|. Here is the simple time chart which tells when each
* callback is invoked:
*
@@ -2971,18 +3070,18 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_EOF`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`
* The remote peer did shutdown on the connection.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`
* Flooding was detected in this HTTP/2 session, and it must be
* closed. This is most likely caused by misbehaviour of peer.
*/
@@ -2992,7 +3091,7 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
* @function
*
* Processes data |in| as an input from the remote endpoint. The
- * |inlen| indicates the number of bytes in the |in|.
+ * |inlen| indicates the number of bytes to receive in the |in|.
*
* This function behaves like `nghttp2_session_recv()` except that it
* does not use :type:`nghttp2_recv_callback` to receive data; the
@@ -3001,27 +3100,27 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
* are called in the same way as they are in `nghttp2_session_recv()`.
*
* In the current implementation, this function always tries to
- * processes all input data unless either an error occurs or
- * :enum:`NGHTTP2_ERR_PAUSE` is returned from
+ * processes |inlen| bytes of input data unless either an error occurs or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from
* :type:`nghttp2_on_header_callback` or
* :type:`nghttp2_on_data_chunk_recv_callback`. If
- * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the
- * number of bytes which was used to produce the data or frame for the
- * callback.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value
+ * includes the number of bytes which was used to produce the data or
+ * frame for the callback.
*
* This function returns the number of processed bytes, or one of the
* following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`
* Flooding was detected in this HTTP/2 session, and it must be
* closed. This is most likely caused by misbehaviour of peer.
*/
@@ -3038,9 +3137,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The stream does not exist; or no deferred data exist.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
@@ -3101,7 +3200,7 @@ nghttp2_session_get_stream_user_data(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The stream does not exist
*/
NGHTTP2_EXTERN int
@@ -3318,7 +3417,7 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
@@ -3345,9 +3444,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |last_stream_id| is invalid.
*/
NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
@@ -3362,7 +3461,7 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
*
* This function is only usable for server. If this function is
* called with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
* To gracefully shutdown HTTP/2 session, server should call this
* function to send GOAWAY with last_stream_id (1u << 31) - 1. And
@@ -3384,9 +3483,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The |session| is initialized as client.
*/
NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
@@ -3421,7 +3520,7 @@ NGHTTP2_EXTERN uint32_t nghttp2_session_get_local_settings(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |next_stream_id| is strictly less than the value
* `nghttp2_session_get_next_stream_id()` returns; or
* |next_stream_id| is invalid (e.g., even integer for client, or
@@ -3456,11 +3555,11 @@ nghttp2_session_get_next_stream_id(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
@@ -3477,9 +3576,9 @@ NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
@@ -3496,11 +3595,11 @@ NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
@@ -3527,12 +3626,17 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Attempted to depend on itself; or no stream exist for the given
* |stream_id|; or |stream_id| is 0
*/
@@ -3570,12 +3674,17 @@ nghttp2_session_change_stream_priority(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Attempted to depend on itself; or stream denoted by |stream_id|
* already exists; or |stream_id| cannot be used to create idle
* stream (in other words, local endpoint has already opened
@@ -3626,11 +3735,11 @@ nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The stream ID 1 is already used or closed; or is not available.
*/
NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
@@ -3670,11 +3779,11 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The stream ID 1 is already used or closed; or is not available.
*/
NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
@@ -3698,10 +3807,10 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
* This function returns the number of bytes written in |buf|, or one
* of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |iv| contains duplicate settings ID or invalid value.
*
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload(
@@ -3732,8 +3841,8 @@ NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code);
* on with |weight| and its exclusive flag. If |exclusive| is
* nonzero, exclusive flag is set.
*
- * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
+ * The |weight| must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.
*/
NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
int32_t stream_id,
@@ -3768,11 +3877,17 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members.
*
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
@@ -3783,12 +3898,12 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|. The order of elements in
* |nva| is preserved. For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively. With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase. The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase. The
+ * application should maintain the references to them until
* :type:`nghttp2_on_frame_send_callback` or
* :type:`nghttp2_on_frame_not_send_callback` is called.
*
@@ -3810,15 +3925,15 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* This function returns assigned stream ID if it succeeds, or one of
* the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Trying to depend on itself (new stream ID equals
* ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is server session.
*
* .. warning::
@@ -3853,12 +3968,12 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|. The order of elements in
* |nva| is preserved. For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively. With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase. The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase. The
+ * application should maintain the references to them until
* :type:`nghttp2_on_frame_send_callback` or
* :type:`nghttp2_on_frame_not_send_callback` is called.
*
@@ -3884,16 +3999,16 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. Normally, this does not happen, but when
* application wrongly calls `nghttp2_submit_response()` twice,
* this may happen.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is client session.
*
* .. warning::
@@ -3919,12 +4034,12 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|. The order of elements in
* |nva| is preserved. For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively. With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase. The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase. The
+ * application should maintain the references to them until
* :type:`nghttp2_on_frame_send_callback` or
* :type:`nghttp2_on_frame_not_send_callback` is called.
*
@@ -3936,16 +4051,16 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* |nva| will be sent as response headers, which will result in error.
*
* This function has the same effect with `nghttp2_submit_headers()`,
- * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and
- * stream_user_data to NULL.
+ * with flags = :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` and both
+ * pri_spec and stream_user_data to NULL.
*
* To submit trailer fields after `nghttp2_submit_response()` is
* called, the application has to specify
* :type:`nghttp2_data_provider` to `nghttp2_submit_response()`.
* Inside of :type:`nghttp2_data_source_read_callback`, when setting
- * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set
- * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`. After that, the
- * application can send trailer fields using
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM`. After
+ * that, the application can send trailer fields using
* `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used
* inside :type:`nghttp2_data_source_read_callback`.
*
@@ -3953,9 +4068,9 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* Otherwise, this function returns 0 if it succeeds, or one of the
* following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
*/
NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
@@ -3968,10 +4083,10 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* Submits HEADERS frame. The |flags| is bitwise OR of the
* following values:
*
- * * :enum:`NGHTTP2_FLAG_END_STREAM`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`
*
- * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
- * END_STREAM flag set.
+ * If |flags| includes :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`,
+ * this frame has END_STREAM flag set.
*
* The library handles the CONTINUATION frame internally and it
* correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE
@@ -3988,11 +4103,16 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members.
*
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
@@ -4003,12 +4123,12 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|. The order of elements in
* |nva| is preserved. For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively. With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase. The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase. The
+ * application should maintain the references to them until
* :type:`nghttp2_on_frame_send_callback` or
* :type:`nghttp2_on_frame_not_send_callback` is called.
*
@@ -4026,19 +4146,19 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* |stream_id| is -1. Otherwise, this function returns 0 if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; or trying to depend on itself (stream ID
* equals ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. This happens if stream denoted by |stream_id|
* is in reserved state.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |stream_id| is -1, and |session| is server session.
*
* .. warning::
@@ -4060,8 +4180,8 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers(
*
* Submits one or more DATA frames to the stream |stream_id|. The
* data to be sent are provided by |data_prd|. If |flags| contains
- * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM
- * flag set.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame
+ * has END_STREAM flag set.
*
* This function does not take ownership of the |data_prd|. The
* function copies the members of the |data_prd|.
@@ -4069,27 +4189,28 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
* .. note::
*
* Currently, only one DATA or HEADERS is allowed for a stream at a
* time. Submitting these frames more than once before first DATA
- * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
- * error code. The earliest callback which tells that previous
- * frame is done is :type:`nghttp2_on_frame_send_callback`. In side
- * that callback, new data can be submitted using
- * `nghttp2_submit_data()`. Of course, all data except for last one
- * must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
- * |flags|. This sounds a bit complicated, and we recommend to use
+ * or HEADERS is finished results in
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code. The
+ * earliest callback which tells that previous frame is done is
+ * :type:`nghttp2_on_frame_send_callback`. In side that callback,
+ * new data can be submitted using `nghttp2_submit_data()`. Of
+ * course, all data except for last one must not have
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|.
+ * This sounds a bit complicated, and we recommend to use
* `nghttp2_submit_request()` and `nghttp2_submit_response()` to
* avoid this cascading issue. The experience shows that for HTTP
* use, these two functions are enough to implement both client and
@@ -4106,25 +4227,31 @@ NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* to the priority specification |pri_spec|.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |pri_spec| is priority specification of this request. ``NULL``
* is not allowed for this function. To specify the priority, use
* `nghttp2_priority_spec_init()`. This function will copy its data
* members.
*
- * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
- * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
- * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
- * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, this function does
+ * nothing and returns 0.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
* depend on itself.
*/
@@ -4134,6 +4261,61 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
const nghttp2_priority_spec *pri_spec);
/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency
+ * level for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level
+ * for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_HIGH 0
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for
+ * :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LOW 7
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency
+ * levels for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1)
+
+/**
+ * @struct
+ *
+ * :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities
+ * specification for a stream.
+ */
+typedef struct nghttp2_extpri {
+ /**
+ * :member:`urgency` is the urgency of a stream, it must be in
+ * [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`,
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the
+ * highest urgency.
+ */
+ uint32_t urgency;
+ /**
+ * :member:`inc` indicates that a content can be processed
+ * incrementally or not. If inc is 0, it cannot be processed
+ * incrementally. If inc is 1, it can be processed incrementally.
+ * Other value is not permitted.
+ */
+ int inc;
+} nghttp2_extpri;
+
+/**
* @function
*
* Submits RST_STREAM frame to cancel/reject the stream |stream_id|
@@ -4142,14 +4324,14 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
* The pre-defined error code is one of :enum:`nghttp2_error_code`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
*/
NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
@@ -4164,7 +4346,7 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* indicates the number of :type:`nghttp2_settings_entry`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This function does not take ownership of the |iv|. This function
* copies all the elements in the |iv|.
@@ -4173,16 +4355,17 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
* RST_STREAM is issued against such a stream.
*
- * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted
- * by the library and application could not send it at its will.
+ * SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is
+ * automatically submitted by the library and application could not
+ * send it at its will.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |iv| contains invalid value (e.g., initial window size
* strictly greater than (1 << 31) - 1.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
@@ -4210,12 +4393,12 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* This function creates copies of all name/value pairs in |nva|. It
* also lower-cases all names in |nva|. The order of elements in
* |nva| is preserved. For header fields with
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
- * and value are not copied respectively. With
- * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
- * pass header field name in lowercase. The application should
- * maintain the references to them until
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application
+ * is responsible to pass header field name in lowercase. The
+ * application should maintain the references to them until
* :type:`nghttp2_on_frame_send_callback` or
* :type:`nghttp2_on_frame_not_send_callback` is called.
*
@@ -4234,18 +4417,18 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* This function returns assigned promised stream ID if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* This function was invoked when |session| is initialized as
* client.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; The |stream_id| does not designate stream
* that peer initiated.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
* .. warning::
@@ -4274,10 +4457,10 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise(
*
* The |flags| is bitwise OR of 0 or more of the following value.
*
- * * :enum:`NGHTTP2_FLAG_ACK`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
*
* Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
- * should be :enum:`NGHTTP2_FLAG_NONE`.
+ * should be :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* If the |opaque_data| is non ``NULL``, then it should point to the 8
* bytes array of memory to specify opaque data to send with PING
@@ -4287,7 +4470,7 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
@@ -4302,7 +4485,7 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
* The pre-defined error code is one of :enum:`nghttp2_error_code`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |last_stream_id| is peer's stream ID or 0. So if |session| is
* initialized as client, |last_stream_id| must be even or 0. If
@@ -4332,9 +4515,9 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |opaque_data_len| is too large; the |last_stream_id| is
* invalid.
*/
@@ -4390,7 +4573,7 @@ nghttp2_session_check_server_session(nghttp2_session *session);
* Submits WINDOW_UPDATE frame.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |stream_id| is the stream ID to send this WINDOW_UPDATE. To
* send connection level WINDOW_UPDATE, specify 0 to |stream_id|.
@@ -4417,9 +4600,9 @@ nghttp2_session_check_server_session(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_FLOW_CONTROL`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOW_CONTROL`
* The local window size overflow or gets negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
@@ -4437,7 +4620,7 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
* to transmission queue.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This sounds similar to `nghttp2_submit_window_update()`, but there
* are 2 differences. The first difference is that this function
@@ -4456,9 +4639,9 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4489,18 +4672,19 @@ nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags,
*
* The standard HTTP/2 frame cannot be sent with this function, so
* |type| must be strictly grater than 0x9. Otherwise, this function
- * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
+ * will fail with error code
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* If :type:`nghttp2_pack_extension_callback` is not set.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* If |type| specifies standard HTTP/2 frame type. The frame
* types in the rage [0x0, 0x9], both inclusive, are standard
* HTTP/2 frame type, and cannot be sent using this function.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
*/
NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
@@ -4514,8 +4698,8 @@ NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
* extension to HTTP/2. If this frame is received, and
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ALTSVC`,
+ * ``nghttp2_extension.payload`` will point to this struct.
*
* It has the following members:
*/
@@ -4549,7 +4733,7 @@ typedef struct {
* `RFC 7383 <https://tools.ietf.org/html/rfc7838#section-4>`_.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |origin| points to the origin this alternative service is
* associated with. The |origin_len| is the length of the origin. If
@@ -4559,16 +4743,16 @@ typedef struct {
*
* The ALTSVC frame is only usable from server side. If this function
* is invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called from client side session
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The sum of |origin_len| and |field_value_len| is larger than
* 16382; or |origin_len| is 0 while |stream_id| is 0; or
* |origin_len| is not 0 while |stream_id| is not 0.
@@ -4607,8 +4791,8 @@ typedef struct {
* If this frame is received, and
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ORIGIN`,
+ * ``nghttp2_extension.payload`` will point to this struct.
*
* It has the following members:
*/
@@ -4632,7 +4816,7 @@ typedef struct {
* `RFC 8336 <https://tools.ietf.org/html/rfc8336>`_.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |ov| points to the array of origins. The |nov| specifies the
* number of origins included in |ov|. This function creates copies
@@ -4640,13 +4824,13 @@ typedef struct {
*
* The ORIGIN frame is only usable by a server. If this function is
* invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called from client side session.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* There are too many origins, or an origin is too large to fit
* into a default frame payload.
*/
@@ -4656,6 +4840,108 @@ NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session,
size_t nov);
/**
+ * @struct
+ *
+ * The payload of PRIORITY_UPDATE frame. PRIORITY_UPDATE frame is a
+ * non-critical extension to HTTP/2. If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`nghttp2_frame_type.NGHTTP2_PRIORITY_UPDATE`,
+ * ``nghttp2_extension.payload`` will point to this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+ /**
+ * The stream ID of the stream whose priority is updated.
+ */
+ int32_t stream_id;
+ /**
+ * The pointer to Priority field value. It is not necessarily
+ * NULL-terminated.
+ */
+ uint8_t *field_value;
+ /**
+ * The length of the :member:`field_value`.
+ */
+ size_t field_value_len;
+} nghttp2_ext_priority_update;
+
+/**
+ * @function
+ *
+ * Submits PRIORITY_UPDATE frame.
+ *
+ * PRIORITY_UPDATE frame is a non-critical extension to HTTP/2, and
+ * defined in :rfc:`9218#section-7.1`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the ID of stream which is prioritized. The
+ * |field_value| points to the Priority field value. The
+ * |field_value_len| is the length of the Priority field value.
+ *
+ * If this function is called by server,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` is returned.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 0 is received by a remote endpoint (or it is omitted),
+ * this function does nothing and returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The function is called from server side session
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * The |field_value_len| is larger than 16380; or |stream_id| is
+ * 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session,
+ uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Changes the priority of the existing stream denoted by |stream_id|.
+ * The new priority is |extpri|. This function is meant to be used by
+ * server for :rfc:`9218` extensible prioritization scheme.
+ *
+ * If |session| is initialized as client, this function returns
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. For client, use
+ * `nghttp2_submit_priority_update()` instead.
+ *
+ * If :member:`extpri->urgency <nghttp2_extpri.urgency>` is out of
+ * bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`.
+ *
+ * If |ignore_client_signal| is nonzero, server starts to ignore
+ * client priority signals for this stream.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is not submitted via `nghttp2_submit_settings()`,
+ * this function does nothing and returns 0.
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The |session| is initialized as client.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * |stream_id| is zero; or a stream denoted by |stream_id| is not
+ * found.
+ */
+NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri,
+ int ignore_client_signal);
+
+/**
* @function
*
* Compares ``lhs->name`` of length ``lhs->namelen`` bytes and
@@ -4766,13 +5052,51 @@ NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
* Returns nonzero if HTTP header field value |value| of length |len|
* is valid according to
* http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * This function is considered obsolete, and application should
+ * consider to use `nghttp2_check_header_value_rfc9113()` instead.
*/
NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
/**
* @function
*
- * Returns nonzero if the |value| which is supposed to the value of
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2, plus
+ * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value,
+ size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :method header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7231#section-4 and
+ * https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
+ */
+NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :path header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3
+ *
+ * |value| is valid if it merely consists of the allowed characters.
+ * In particular, it does not check whether |value| follows the syntax
+ * of path. The allowed characters are all characters valid by
+ * `nghttp2_check_header_value` minus SPC and HT.
+ */
+NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of the
* :authority or host header field is valid according to
* https://tools.ietf.org/html/rfc3986#section-3.2
*
@@ -4806,7 +5130,7 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4860,7 +5184,7 @@ NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4874,24 +5198,24 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
* the |buf| of length |buflen|.
*
* If |buf| is not large enough to store the deflated header block,
- * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The
- * caller should use `nghttp2_hd_deflate_bound()` to know the upper
- * bound of buffer size required to deflate given header name/value
- * pairs.
+ * this function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
+ * should use `nghttp2_hd_deflate_bound()` to know the upper bound of
+ * buffer size required to deflate given header name/value pairs.
*
* Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
*
* After this function returns, it is safe to delete the |nva|.
*
* This function returns the number of bytes written to |buf| if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
@@ -4907,23 +5231,24 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
* must be set in len field of :type:`nghttp2_vec`. If and only if
* one chunk is filled up completely, next chunk will be used. If
* |vec| is not large enough to store the deflated header block, this
- * function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
+ * function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
* should use `nghttp2_hd_deflate_bound()` to know the upper bound of
* buffer size required to deflate given header name/value pairs.
*
* Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
*
* After this function returns, it is safe to delete the |nva|.
*
* This function returns the number of bytes written to |vec| if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
@@ -5003,7 +5328,7 @@ typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
@@ -5052,9 +5377,9 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called while header block is being inflated.
* Probably, application missed to call
* `nghttp2_hd_inflate_end_headers()`.
@@ -5092,7 +5417,8 @@ typedef enum {
*
* Inflates name/value block stored in |in| with length |inlen|. This
* function performs decompression. For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
* |*inflate_flags| and name/value pair is assigned to the |nv_out|
* and the function returns. The caller must not free the members of
* |nv_out|.
@@ -5115,11 +5441,11 @@ typedef enum {
* This function returns the number of bytes processed if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
* The header field name or value is too large.
*
* Example follows::
@@ -5174,7 +5500,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
*
* Inflates name/value block stored in |in| with length |inlen|. This
* function performs decompression. For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
* |*inflate_flags| and name/value pair is assigned to the |nv_out|
* and the function returns. The caller must not free the members of
* |nv_out|.
@@ -5190,8 +5517,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
* for the next header block input.
*
* In other words, if |in_final| is nonzero, and this function returns
- * |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is
- * set in |*inflate_flags|.
+ * |inlen|, you can assert that
+ * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in
+ * |*inflate_flags|.
*
* The caller can feed complete compressed header block. It also can
* feed it in several chunks. The caller must set |in_final| to
@@ -5201,11 +5529,11 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
* This function returns the number of bytes processed if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
* The header field name or value is too large.
*
* Example follows::
@@ -5376,7 +5704,7 @@ typedef enum {
*
* Returns state of |stream|. The root stream retrieved by
* `nghttp2_session_get_root_stream()` will have stream state
- * :enum:`NGHTTP2_STREAM_STATE_IDLE`.
+ * :enum:`nghttp2_stream_proto_state.NGHTTP2_STREAM_STATE_IDLE`.
*/
NGHTTP2_EXTERN nghttp2_stream_proto_state
nghttp2_stream_get_state(nghttp2_stream *stream);
diff --git a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h
index 45d21e2..6ed0ac4 100644
--- a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h
+++ b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2ver.h
@@ -29,7 +29,7 @@
* @macro
* Version number of the nghttp2 library release
*/
-#define NGHTTP2_VERSION "1.40.0"
+#define NGHTTP2_VERSION "1.52.0"
/**
* @macro
@@ -37,6 +37,6 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define NGHTTP2_VERSION_NUM 0x012800
+#define NGHTTP2_VERSION_NUM 0x013400
#endif /* NGHTTP2VER_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.c b/Utilities/cmnghttp2/lib/nghttp2_buf.c
index 2a435be..a328447 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.c
@@ -82,8 +82,10 @@ void nghttp2_buf_reset(nghttp2_buf *buf) {
}
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
- buf->begin = buf->pos = buf->last = buf->mark = begin;
- buf->end = begin + len;
+ buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
+ if (len) {
+ buf->end += len;
+ }
}
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.h b/Utilities/cmnghttp2/lib/nghttp2_buf.h
index 06cce67..45f62f1 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.h
@@ -99,7 +99,7 @@ void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
* |new_cap|. If extensions took place, buffer pointers in |buf| will
* change.
*
- * This function returns 0 if it succeeds, or one of the followings
+ * This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.c b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
new file mode 100644
index 0000000..3fd9b78
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
@@ -0,0 +1,35 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * 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.
+ */
+#include "nghttp2_extpri.h"
+
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
+ return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
+}
+
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
+ extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
+ extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.h b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
new file mode 100644
index 0000000..23c6ddc
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
@@ -0,0 +1,65 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * 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.
+ */
+#ifndef NGHTTP2_EXTPRI_H
+#define NGHTTP2_EXTPRI_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
+ * from a value produced by nghttp2_extpri_to_uint8.
+ */
+#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
+
+/*
+ * nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
+ */
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
+
+/*
+ * nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
+ * nghttp2_extpri_to_uint8, intto |extpri|.
+ */
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
+
+/*
+ * nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
+ * supposed to be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_urgency(PRI) \
+ ((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
+
+/*
+ * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
+ * be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
+
+#endif /* NGHTTP2_EXTPRI_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.c b/Utilities/cmnghttp2/lib/nghttp2_frame.c
index 4821de4..35072c1 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.c
@@ -253,6 +253,31 @@ void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
nghttp2_mem_free(mem, origin->ov);
}
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_ext_priority_update *priority_update;
+
+ nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
+ NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
+
+ priority_update = frame->payload;
+ priority_update->stream_id = stream_id;
+ priority_update->field_value = field_value;
+ priority_update->field_value_len = field_value_len;
+}
+
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem) {
+ nghttp2_ext_priority_update *priority_update;
+
+ priority_update = frame->payload;
+ if (priority_update == NULL) {
+ return;
+ }
+ nghttp2_mem_free(mem, priority_update->field_value);
+}
+
size_t nghttp2_frame_priority_len(uint8_t flags) {
if (flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_PRIORITY_SPECLEN;
@@ -654,8 +679,6 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
var_gift_payloadlen = 0;
}
- payloadlen -= var_gift_payloadlen;
-
if (!var_gift_payloadlen) {
var_gift_payload = NULL;
} else {
@@ -818,8 +841,10 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
size_t len = 0;
origin = frame->payload;
- p = payload;
- end = p + payloadlen;
+ p = end = payload;
+ if (payloadlen) {
+ end += payloadlen;
+ }
for (; p != end;) {
if (end - p < 2) {
@@ -876,6 +901,57 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
return 0;
}
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *frame) {
+ int rv;
+ nghttp2_buf *buf;
+ nghttp2_ext_priority_update *priority_update;
+
+ /* This is required with --disable-assert. */
+ (void)rv;
+
+ priority_update = frame->payload;
+
+ buf = &bufs->head->buf;
+
+ assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
+
+ buf->pos -= NGHTTP2_FRAME_HDLEN;
+
+ nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
+
+ nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
+ buf->last += 4;
+
+ rv = nghttp2_bufs_add(bufs, priority_update->field_value,
+ priority_update->field_value_len);
+
+ assert(rv == 0);
+
+ return 0;
+}
+
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen) {
+ nghttp2_ext_priority_update *priority_update;
+
+ assert(payloadlen >= 4);
+
+ priority_update = frame->payload;
+
+ priority_update->stream_id =
+ nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
+
+ if (payloadlen > 4) {
+ priority_update->field_value = payload + 4;
+ priority_update->field_value_len = payloadlen - 4;
+ } else {
+ priority_update->field_value = NULL;
+ priority_update->field_value_len = 0;
+ }
+}
+
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem) {
nghttp2_settings_entry *iv_copy;
@@ -897,9 +973,25 @@ nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
}
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
- return a->namelen == b->namelen && a->valuelen == b->valuelen &&
- memcmp(a->name, b->name, a->namelen) == 0 &&
- memcmp(a->value, b->value, a->valuelen) == 0;
+ if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
+ return 0;
+ }
+
+ if (a->name == NULL || b->name == NULL) {
+ assert(a->namelen == 0);
+ assert(b->namelen == 0);
+ } else if (memcmp(a->name, b->name, a->namelen) != 0) {
+ return 0;
+ }
+
+ if (a->value == NULL || b->value == NULL) {
+ assert(a->valuelen == 0);
+ assert(b->valuelen == 0);
+ } else if (memcmp(a->value, b->value, a->valuelen) != 0) {
+ return 0;
+ }
+
+ return 1;
}
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
@@ -1055,6 +1147,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
return 0;
}
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ if (iv[i].value != 0 && iv[i].value != 1) {
+ return 0;
+ }
+ break;
}
}
return 1;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.h b/Utilities/cmnghttp2/lib/nghttp2_frame.h
index 615bbf3..5f6152b 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.h
@@ -46,7 +46,7 @@
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
#define NGHTTP2_MAX_PAYLOADLEN 16384
-/* The one frame buffer length for tranmission. We may use several of
+/* The one frame buffer length for transmission. We may use several of
them to support CONTINUATION. To account for Pad Length field, we
allocate extra 1 byte, which saves extra large memcopying. */
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
@@ -57,7 +57,7 @@
/* Maximum headers block size to send, calculated using
nghttp2_hd_deflate_bound(). This is the default value, and can be
- overridden by nghttp2_option_set_max_send_header_block_size(). */
+ overridden by nghttp2_option_set_max_send_header_block_length(). */
#define NGHTTP2_MAX_HEADERSLEN 65536
/* The number of bytes for each SETTINGS entry */
@@ -73,6 +73,7 @@
typedef union {
nghttp2_ext_altsvc altsvc;
nghttp2_ext_origin origin;
+ nghttp2_ext_priority_update priority_update;
} nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
@@ -423,6 +424,31 @@ int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PRIORITY_UPDATE frame |frame| in wire frame format and store
+ * it in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *ext);
+
+/*
+ * Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of
+ * |payloadlen| bytes contains frame payload. This function assumes
+ * that frame->payload points to the nghttp2_ext_priority_update
+ * object.
+ *
+ * This function always succeeds and returns 0.
+ */
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen);
+
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
@@ -539,6 +565,25 @@ void nghttp2_frame_origin_init(nghttp2_extension *frame,
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
/*
+ * Initializes PRIORITY_UPDATE frame |frame| with given values. This
+ * function assumes that frame->payload points to
+ * nghttp2_ext_priority_update object. On success, this function
+ * takes ownership of |field_value|, so caller must not free it.
+ */
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|. This function does not free
+ * nghttp2_ext_priority_update object pointed by frame->payload. This
+ * function only frees field_value pointed by
+ * nghttp2_ext_priority_update.field_value.
+ */
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem);
+
+/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
* not include the Pad Length field. If |padlen| is 0, this function
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.c b/Utilities/cmnghttp2/lib/nghttp2_hd.c
index 5e86931..8a2bda6 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.c
@@ -269,6 +269,11 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_LOCATION;
}
break;
+ case 'y':
+ if (memeq("priorit", name, 7)) {
+ return NGHTTP2_TOKEN_PRIORITY;
+ }
+ break;
}
break;
case 9:
@@ -1263,6 +1268,8 @@ int nghttp2_hd_inflate_change_table_size(
return NGHTTP2_ERR_INVALID_STATE;
}
+ inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
+
/* It seems that encoder is not required to send dynamic table size
update if the table size is not changed after applying
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
@@ -1275,13 +1282,12 @@ int nghttp2_hd_inflate_change_table_size(
/* Remember minimum value, and validate that encoder sends the
value less than or equal to this. */
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
- }
- inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
+ inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
- inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
+ hd_context_shrink_table_size(&inflater->ctx, NULL);
+ }
- hd_context_shrink_table_size(&inflater->ctx, NULL);
return 0;
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.h b/Utilities/cmnghttp2/lib/nghttp2_hd.h
index 2674028..6de0052 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.h
@@ -112,6 +112,7 @@ typedef enum {
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN__PROTOCOL,
+ NGHTTP2_TOKEN_PRIORITY,
} nghttp2_token;
struct nghttp2_hd_entry;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_helper.c b/Utilities/cmnghttp2/lib/nghttp2_helper.c
index 91136a6..93dd475 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_helper.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_helper.c
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
case NGHTTP2_ERR_FLOODED:
return "Flooding was detected in this HTTP/2 session, and it must be "
"closed";
+ case NGHTTP2_ERR_TOO_MANY_SETTINGS:
+ return "SETTINGS frame contained more than the maximum allowed entries";
default:
return "Unknown error code";
}
@@ -505,7 +507,179 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
return 1;
}
-/* Generated by genauthroitychartbl.py */
+int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
+ if (len == 0) {
+ return 1;
+ }
+
+ if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
+ *(value + len - 1) == '\t') {
+ return 0;
+ }
+
+ return nghttp2_check_header_value(value, len);
+}
+
+/* Generated by genmethodchartbl.py */
+static char VALID_METHOD_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
+ 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
+ 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
+ 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
+ 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
+ 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
+ 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
+ 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
+ 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
+ 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
+ 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
+ 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
+ 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
+ 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
+ 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
+ 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
+ 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
+ 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
+ 1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
+ 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
+ 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
+ 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
+ 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
+ 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
+ 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
+ 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
+ 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
+ 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
+ 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
+ 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
+ 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
+ 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
+ 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
+ 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
+ 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
+ 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
+ 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
+ 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
+ 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
+ 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
+ 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
+ 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
+ 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
+ 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
+ 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
+ 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
+ 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
+ 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
+ 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
+ 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
+ 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
+ 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
+};
+
+int nghttp2_check_method(const uint8_t *value, size_t len) {
+ const uint8_t *last;
+ if (len == 0) {
+ return 0;
+ }
+ for (last = value + len; value != last; ++value) {
+ if (!VALID_METHOD_CHARS[*value]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Generated by genpathchartbl.py */
+static char VALID_PATH_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
+ 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
+ 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
+ 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
+ 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
+ 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
+ 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
+ 0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
+ 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
+ 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
+ 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
+ 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
+ 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
+ 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
+ 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
+ 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
+ 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
+ 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
+ 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
+ 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
+ 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
+ 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
+ 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
+ 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
+ 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
+ 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
+ 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
+ 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
+ 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
+ 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
+ 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
+ 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
+ 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
+ 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
+ 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
+ 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
+ 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
+ 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
+ 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
+ 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
+ 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
+ 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
+ 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
+ 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
+ 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
+ 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
+ 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
+ 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
+ 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
+ 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
+ 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
+ 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
+ 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
+ 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
+ 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
+ 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
+ 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
+ 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
+ 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
+};
+
+int nghttp2_check_path(const uint8_t *value, size_t len) {
+ const uint8_t *last;
+ for (last = value + len; value != last; ++value) {
+ if (!VALID_PATH_CHARS[*value]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Generated by genauthoritychartbl.py */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.c b/Utilities/cmnghttp2/lib/nghttp2_http.c
index 62f57b6..83e5e66 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.c
@@ -30,6 +30,7 @@
#include "nghttp2_hd.h"
#include "nghttp2_helper.h"
+#include "nghttp2_extpri.h"
static uint8_t downcase(uint8_t c) {
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
@@ -72,25 +73,12 @@ static int64_t parse_uint(const uint8_t *s, size_t len) {
return n;
}
-static int lws(const uint8_t *s, size_t n) {
- size_t i;
- for (i = 0; i < n; ++i) {
- if (s[i] != ' ' && s[i] != '\t') {
- return 0;
- }
- }
- return 1;
-}
-
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
- int flag) {
- if (stream->http_flags & flag) {
- return 0;
- }
- if (lws(nv->value->base, nv->value->len)) {
+ uint32_t flag) {
+ if ((stream->http_flags & flag) || nv->value->len == 0) {
return 0;
}
- stream->http_flags = (uint16_t)(stream->http_flags | flag);
+ stream->http_flags = stream->http_flags | flag;
return 1;
}
@@ -114,6 +102,8 @@ static int check_path(nghttp2_stream *stream) {
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer, int connect_protocol) {
+ nghttp2_extpri extpri;
+
if (nv->name->base[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -212,6 +202,23 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
+ case NGHTTP2_TOKEN_PRIORITY:
+ if (!trailer &&
+ /* Do not parse the header field in PUSH_PROMISE. */
+ (stream->stream_id & 1) &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
+ nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
+ if (nghttp2_http_parse_priority(&extpri, nv->value->base,
+ nv->value->len) == 0) {
+ stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
+ } else {
+ stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
+ }
+ }
+ break;
default:
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
@@ -329,6 +336,16 @@ static int check_scheme(const uint8_t *value, size_t len) {
return 1;
}
+static int lws(const uint8_t *s, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ if (s[i] != ' ' && s[i] != '\t') {
+ return 0;
+ }
+ }
+ return 1;
+}
+
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer) {
@@ -360,13 +377,46 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
- if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
- nv->token == NGHTTP2_TOKEN_HOST) {
- rv = nghttp2_check_authority(nv->value->base, nv->value->len);
- } else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
+ switch (nv->token) {
+ case NGHTTP2_TOKEN__METHOD:
+ rv = nghttp2_check_method(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__PATH:
+ rv = nghttp2_check_path(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__AUTHORITY:
+ case NGHTTP2_TOKEN_HOST:
+ if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+ rv = nghttp2_check_authority(nv->value->base, nv->value->len);
+ } else if (
+ stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
+ break;
+ case NGHTTP2_TOKEN__SCHEME:
rv = check_scheme(nv->value->base, nv->value->len);
- } else {
- rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__PROTOCOL:
+ /* Check the value consists of just white spaces, which was done
+ in check_pseudo_header before
+ nghttp2_check_header_value_rfc9113 has been introduced. */
+ if ((stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ lws(nv->value->base, nv->value->len)) {
+ rv = 0;
+ break;
+ }
+ /* fall through */
+ default:
+ if (stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
}
if (rv == 0) {
@@ -434,16 +484,15 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
if (stream->status_code / 100 == 1) {
/* non-final response */
- stream->http_flags =
- (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
- NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
+ NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
stream->content_length = -1;
stream->status_code = -1;
return 0;
}
stream->http_flags =
- (uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
if (!expect_response_body(stream)) {
stream->content_length = 0;
@@ -528,3 +577,715 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
return;
}
}
+
+/* Generated by genchartbl.py */
+static const int SF_KEY_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
+ 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */,
+ 1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
+ 0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
+ 0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
+ 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
+ 0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
+ 0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
+ 1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
+ 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if ((*p < 'a' || 'z' < *p) && *p != '*') {
+ return -1;
+ }
+
+ for (; p != end && SF_KEY_CHARS[*p]; ++p)
+ ;
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
+ const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ int sign = 1;
+ int64_t value = 0;
+ int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
+ size_t len = 0;
+ size_t fpos = 0;
+ size_t i;
+
+ if (*p == '-') {
+ if (++p == end) {
+ return -1;
+ }
+
+ sign = -1;
+ }
+
+ if (*p < '0' || '9' < *p) {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value *= 10;
+ value += *p - '0';
+
+ if (++len > 15) {
+ return -1;
+ }
+
+ break;
+ case '.':
+ if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
+ goto fin;
+ }
+
+ if (len > 12) {
+ return -1;
+ }
+ fpos = len;
+ type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
+
+ break;
+ default:
+ goto fin;
+ };
+ }
+
+fin:
+ switch (type) {
+ case NGHTTP2_SF_VALUE_TYPE_INTEGER:
+ if (dest) {
+ dest->type = (uint8_t)type;
+ dest->i = value * sign;
+ }
+
+ return p - begin;
+ case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
+ if (fpos == len || len - fpos > 3) {
+ return -1;
+ }
+
+ if (dest) {
+ dest->type = (uint8_t)type;
+ dest->d = (double)value;
+ for (i = len - fpos; i > 0; --i) {
+ dest->d /= (double)10;
+ }
+ dest->d *= sign;
+ }
+
+ return p - begin;
+ default:
+ assert(0);
+ abort();
+ }
+}
+
+/* Generated by genchartbl.py */
+static const int SF_DQUOTE_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */,
+ 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
+ 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
+ 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */,
+ 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
+ 1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if (*p++ != '"') {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case '\\':
+ if (++p == end) {
+ return -1;
+ }
+
+ switch (*p) {
+ case '"':
+ case '\\':
+ break;
+ default:
+ return -1;
+ }
+
+ break;
+ case '"':
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
+ dest->s.base = begin + 1;
+ dest->s.len = (size_t)(p - dest->s.base);
+ }
+
+ ++p;
+
+ return p - begin;
+ default:
+ if (!SF_DQUOTE_CHARS[*p]) {
+ return -1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_TOKEN_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
+ 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
+ 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
+ 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
+ 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
+ return -1;
+ }
+
+ for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
+ ;
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
+ dest->s.base = begin;
+ dest->s.len = (size_t)(p - begin);
+ }
+
+ return p - begin;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_BYTESEQ_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
+ 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
+ 0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */,
+ 0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
+ 0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
+ 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if (*p++ != ':') {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case ':':
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
+ dest->s.base = begin + 1;
+ dest->s.len = (size_t)(p - dest->s.base);
+ }
+
+ ++p;
+
+ return p - begin;
+ default:
+ if (!SF_BYTESEQ_CHARS[*p]) {
+ return -1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ int b;
+
+ if (*p++ != '?') {
+ return -1;
+ }
+
+ if (p == end) {
+ return -1;
+ }
+
+ switch (*p++) {
+ case '0':
+ b = 0;
+ break;
+ case '1':
+ b = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+ dest->b = b;
+ }
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ switch (*begin) {
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return sf_parse_integer_or_decimal(dest, begin, end);
+ case '"':
+ return sf_parse_string(dest, begin, end);
+ case '*':
+ return sf_parse_token(dest, begin, end);
+ case ':':
+ return sf_parse_byteseq(dest, begin, end);
+ case '?':
+ return sf_parse_boolean(dest, begin, end);
+ default:
+ if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
+ return sf_parse_token(dest, begin, end);
+ }
+ return -1;
+ }
+}
+
+#define sf_discard_sp_end_err(BEGIN, END, ERR) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ return (ERR); \
+ } \
+ if (*(BEGIN) != ' ') { \
+ break; \
+ } \
+ }
+
+static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ for (; p != end && *p == ';';) {
+ ++p;
+
+ sf_discard_sp_end_err(p, end, -1);
+
+ slen = sf_parse_key(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (p == end || *p != '=') {
+ /* Boolean true */
+ } else if (++p == end) {
+ return -1;
+ } else {
+ slen = sf_parse_bare_item(NULL, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+ }
+ }
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ slen = sf_parse_bare_item(dest, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ return p - begin;
+}
+
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ return sf_parse_item(dest, begin, end);
+}
+
+static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ if (*p++ != '(') {
+ return -1;
+ }
+
+ for (;;) {
+ sf_discard_sp_end_err(p, end, -1);
+
+ if (*p == ')') {
+ ++p;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
+ }
+
+ return p - begin;
+ }
+
+ slen = sf_parse_item(NULL, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (p == end || (*p != ' ' && *p != ')')) {
+ return -1;
+ }
+ }
+}
+
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin, const uint8_t *end) {
+ return sf_parse_inner_list(dest, begin, end);
+}
+
+static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin,
+ const uint8_t *end) {
+ if (*begin == '(') {
+ return sf_parse_inner_list(dest, begin, end);
+ }
+
+ return sf_parse_item(dest, begin, end);
+}
+
+#define sf_discard_ows(BEGIN, END) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ goto fin; \
+ } \
+ if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
+ break; \
+ } \
+ }
+
+#define sf_discard_ows_end_err(BEGIN, END, ERR) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ return (ERR); \
+ } \
+ if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
+ break; \
+ } \
+ }
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+ size_t valuelen) {
+ const uint8_t *p = value, *end = value + valuelen;
+ ssize_t slen;
+ nghttp2_sf_value val;
+ nghttp2_extpri pri = *dest;
+ const uint8_t *key;
+ size_t keylen;
+
+ for (; p != end && *p == ' '; ++p)
+ ;
+
+ for (; p != end;) {
+ slen = sf_parse_key(p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ key = p;
+ keylen = (size_t)slen;
+
+ p += slen;
+
+ if (p == end || *p != '=') {
+ /* Boolean true */
+ val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+ val.b = 1;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ } else if (++p == end) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ } else {
+ slen = sf_parse_item_or_inner_list(&val, p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ }
+
+ p += slen;
+
+ if (keylen == 1) {
+ switch (key[0]) {
+ case 'i':
+ if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.inc = val.b;
+
+ break;
+ case 'u':
+ if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
+ val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
+ NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.urgency = (uint32_t)val.i;
+
+ break;
+ }
+ }
+
+ sf_discard_ows(p, end);
+
+ if (*p++ != ',') {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
+ }
+
+fin:
+ *dest = pri;
+
+ return 0;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.h b/Utilities/cmnghttp2/lib/nghttp2_http.h
index dd057cd..0c3a78e 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.h
@@ -94,4 +94,55 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
void nghttp2_http_record_request_method(nghttp2_stream *stream,
nghttp2_frame *frame);
+/*
+ * RFC 8941 Structured Field Values.
+ */
+typedef enum nghttp2_sf_value_type {
+ NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
+ NGHTTP2_SF_VALUE_TYPE_INTEGER,
+ NGHTTP2_SF_VALUE_TYPE_DECIMAL,
+ NGHTTP2_SF_VALUE_TYPE_STRING,
+ NGHTTP2_SF_VALUE_TYPE_TOKEN,
+ NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
+ NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
+} nghttp2_sf_value_type;
+
+/*
+ * nghttp2_sf_value stores Structured Field Values item. For Inner
+ * List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
+ */
+typedef struct nghttp2_sf_value {
+ uint8_t type;
+ union {
+ int b;
+ int64_t i;
+ double d;
+ struct {
+ const uint8_t *base;
+ size_t len;
+ } s;
+ };
+} nghttp2_sf_value;
+
+/*
+ * nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Item in |dest|. It returns the number of
+ * bytes consumed if it succeeds, or -1. This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end);
+
+/*
+ * nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Inner List in |dest|. It returns the number of
+ * bytes consumed if it succeeds, or -1. This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin, const uint8_t *end);
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+ size_t valuelen);
+
#endif /* NGHTTP2_HTTP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.c b/Utilities/cmnghttp2/lib/nghttp2_map.c
index 4d9f97b..e5db168 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.c
@@ -1,7 +1,8 @@
/*
* nghttp2 - HTTP/2 C Library
*
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -25,14 +26,19 @@
#include "nghttp2_map.h"
#include <string.h>
+#include <assert.h>
+#include <stdio.h>
-#define INITIAL_TABLE_LENGTH 256
+#include "nghttp2_helper.h"
+
+#define NGHTTP2_INITIAL_TABLE_LENBITS 8
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
- map->tablelen = INITIAL_TABLE_LENGTH;
+ map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
+ map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
map->table =
- nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *));
+ nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
if (map->table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
@@ -43,112 +49,188 @@ int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
}
void nghttp2_map_free(nghttp2_map *map) {
+ if (!map) {
+ return;
+ }
+
nghttp2_mem_free(map->mem, map->table);
}
-void nghttp2_map_each_free(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
uint32_t i;
+ nghttp2_map_bucket *bkt;
+
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- nghttp2_map_entry *next = entry->next;
- func(entry, ptr);
- entry = next;
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ continue;
}
- map->table[i] = NULL;
+
+ func(bkt->data, ptr);
}
}
-int nghttp2_map_each(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
uint32_t i;
+ nghttp2_map_bucket *bkt;
+
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry; entry = entry->next) {
- rv = func(entry, ptr);
- if (rv != 0) {
- return rv;
- }
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ continue;
+ }
+
+ rv = func(bkt->data, ptr);
+ if (rv != 0) {
+ return rv;
}
}
+
return 0;
}
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
- entry->key = key;
- entry->next = NULL;
+static uint32_t hash(nghttp2_map_key_type key) {
+ return (uint32_t)key * 2654435769u;
}
-/* Same hash function in android HashMap source code. */
-/* The |mod| must be power of 2 */
-static uint32_t hash(int32_t key, uint32_t mod) {
- uint32_t h = (uint32_t)key;
- h ^= (h >> 20) ^ (h >> 12);
- h ^= (h >> 7) ^ (h >> 4);
- return h & (mod - 1);
+static size_t h2idx(uint32_t hash, uint32_t bits) {
+ return hash >> (32 - bits);
}
-static int insert(nghttp2_map_entry **table, uint32_t tablelen,
- nghttp2_map_entry *entry) {
- uint32_t h = hash(entry->key, tablelen);
- if (table[h] == NULL) {
- table[h] = entry;
- } else {
- nghttp2_map_entry *p;
- /* We won't allow duplicated key, so check it out. */
- for (p = table[h]; p; p = p->next) {
- if (p->key == entry->key) {
- return NGHTTP2_ERR_INVALID_ARGUMENT;
- }
+static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
+ nghttp2_map_bucket *bkt, size_t idx) {
+ return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
+}
+
+static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
+ nghttp2_map_key_type *pkey, void **pdata) {
+ uint32_t h = bkt->hash;
+ nghttp2_map_key_type key = bkt->key;
+ void *data = bkt->data;
+
+ bkt->hash = *phash;
+ bkt->key = *pkey;
+ bkt->data = *pdata;
+
+ *phash = h;
+ *pkey = key;
+ *pdata = data;
+}
+
+static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
+ nghttp2_map_key_type key, void *data) {
+ bkt->hash = hash;
+ bkt->key = key;
+ bkt->data = data;
+}
+
+void nghttp2_map_print_distance(nghttp2_map *map) {
+ uint32_t i;
+ size_t idx;
+ nghttp2_map_bucket *bkt;
+
+ for (i = 0; i < map->tablelen; ++i) {
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ fprintf(stderr, "@%u <EMPTY>\n", i);
+ continue;
}
- entry->next = table[h];
- table[h] = entry;
+
+ idx = h2idx(bkt->hash, map->tablelenbits);
+ fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
+ bkt->hash, bkt->key, idx,
+ distance(map->tablelen, map->tablelenbits, bkt, idx));
+ }
+}
+
+static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
+ uint32_t tablelenbits, uint32_t hash,
+ nghttp2_map_key_type key, void *data) {
+ size_t idx = h2idx(hash, tablelenbits);
+ size_t d = 0, dd;
+ nghttp2_map_bucket *bkt;
+
+ for (;;) {
+ bkt = &table[idx];
+
+ if (bkt->data == NULL) {
+ map_bucket_set_data(bkt, hash, key, data);
+ return 0;
+ }
+
+ dd = distance(tablelen, tablelenbits, bkt, idx);
+ if (d > dd) {
+ map_bucket_swap(bkt, &hash, &key, &data);
+ d = dd;
+ } else if (bkt->key == key) {
+ /* TODO This check is just a waste after first swap or if this
+ function is called from map_resize. That said, there is no
+ difference with or without this conditional in performance
+ wise. */
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ ++d;
+ idx = (idx + 1) & (tablelen - 1);
}
- return 0;
}
-/* new_tablelen must be power of 2 */
-static int resize(nghttp2_map *map, uint32_t new_tablelen) {
+/* new_tablelen must be power of 2 and new_tablelen == (1 <<
+ new_tablelenbits) must hold. */
+static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
+ uint32_t new_tablelenbits) {
uint32_t i;
- nghttp2_map_entry **new_table;
+ nghttp2_map_bucket *new_table;
+ nghttp2_map_bucket *bkt;
+ int rv;
+ (void)rv;
new_table =
- nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *));
+ nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
if (new_table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- nghttp2_map_entry *next = entry->next;
- entry->next = NULL;
- /* This function must succeed */
- insert(new_table, new_tablelen, entry);
- entry = next;
+ bkt = &map->table[i];
+ if (bkt->data == NULL) {
+ continue;
}
+ rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
+ bkt->data);
+
+ assert(0 == rv);
}
+
nghttp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
+ map->tablelenbits = new_tablelenbits;
map->table = new_table;
return 0;
}
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
int rv;
+
+ assert(data);
+
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
- rv = resize(map, map->tablelen * 2);
+ rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
if (rv != 0) {
return rv;
}
}
- rv = insert(map->table, map->tablelen, new_entry);
+
+ rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
+ data);
if (rv != 0) {
return rv;
}
@@ -156,34 +238,76 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
return 0;
}
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
- uint32_t h;
- nghttp2_map_entry *entry;
- h = hash(key, map->tablelen);
- for (entry = map->table[h]; entry; entry = entry->next) {
- if (entry->key == key) {
- return entry;
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
+ uint32_t h = hash(key);
+ size_t idx = h2idx(h, map->tablelenbits);
+ nghttp2_map_bucket *bkt;
+ size_t d = 0;
+
+ for (;;) {
+ bkt = &map->table[idx];
+
+ if (bkt->data == NULL ||
+ d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+ return NULL;
}
+
+ if (bkt->key == key) {
+ return bkt->data;
+ }
+
+ ++d;
+ idx = (idx + 1) & (map->tablelen - 1);
}
- return NULL;
}
-int nghttp2_map_remove(nghttp2_map *map, key_type key) {
- uint32_t h;
- nghttp2_map_entry **dst;
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
+ uint32_t h = hash(key);
+ size_t idx = h2idx(h, map->tablelenbits), didx;
+ nghttp2_map_bucket *bkt;
+ size_t d = 0;
- h = hash(key, map->tablelen);
+ for (;;) {
+ bkt = &map->table[idx];
- for (dst = &map->table[h]; *dst; dst = &(*dst)->next) {
- if ((*dst)->key != key) {
- continue;
+ if (bkt->data == NULL ||
+ d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (bkt->key == key) {
+ map_bucket_set_data(bkt, 0, 0, NULL);
+
+ didx = idx;
+ idx = (idx + 1) & (map->tablelen - 1);
+
+ for (;;) {
+ bkt = &map->table[idx];
+ if (bkt->data == NULL ||
+ distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
+ break;
+ }
+
+ map->table[didx] = *bkt;
+ map_bucket_set_data(bkt, 0, 0, NULL);
+ didx = idx;
+
+ idx = (idx + 1) & (map->tablelen - 1);
+ }
+
+ --map->size;
+
+ return 0;
}
- *dst = (*dst)->next;
- --map->size;
- return 0;
+ ++d;
+ idx = (idx + 1) & (map->tablelen - 1);
}
- return NGHTTP2_ERR_INVALID_ARGUMENT;
+}
+
+void nghttp2_map_clear(nghttp2_map *map) {
+ memset(map->table, 0, sizeof(*map->table) * map->tablelen);
+ map->size = 0;
}
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.h b/Utilities/cmnghttp2/lib/nghttp2_map.h
index f6e29e3..1419a09 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.h
@@ -1,7 +1,8 @@
/*
* nghttp2 - HTTP/2 C Library
*
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -30,27 +31,25 @@
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
-#include "nghttp2_int.h"
+
#include "nghttp2_mem.h"
/* Implementation of unordered map */
-typedef int32_t key_type;
+typedef int32_t nghttp2_map_key_type;
-typedef struct nghttp2_map_entry {
- struct nghttp2_map_entry *next;
- key_type key;
-#if SIZEOF_INT_P == 4
- /* we requires 8 bytes aligment */
- int64_t pad;
-#endif
-} nghttp2_map_entry;
+typedef struct nghttp2_map_bucket {
+ uint32_t hash;
+ nghttp2_map_key_type key;
+ void *data;
+} nghttp2_map_bucket;
-typedef struct {
- nghttp2_map_entry **table;
+typedef struct nghttp2_map {
+ nghttp2_map_bucket *table;
nghttp2_mem *mem;
size_t size;
uint32_t tablelen;
+ uint32_t tablelenbits;
} nghttp2_map;
/*
@@ -74,21 +73,14 @@ void nghttp2_map_free(nghttp2_map *map);
/*
* Deallocates each entries using |func| function and any resources
* allocated for |map|. The |func| function is responsible for freeing
- * given the |entry| object. The |ptr| will be passed to the |func| as
+ * given the |data| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
-void nghttp2_map_each_free(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
/*
- * Initializes the |entry| with the |key|. All entries to be inserted
- * to the map must be initialized with this function.
- */
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
-
-/*
- * Inserts the new |entry| with the key |entry->key| to the map |map|.
+ * Inserts the new |data| with the |key| to the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -98,25 +90,30 @@ void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
/*
- * Returns the entry associated by the key |key|. If there is no such
- * entry, this function returns NULL.
+ * Returns the data associated by the key |key|. If there is no such
+ * data, this function returns NULL.
*/
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
/*
- * Removes the entry associated by the key |key| from the |map|. The
- * removed entry is not freed by this function.
+ * Removes the data associated by the key |key| from the |map|. The
+ * removed data is not freed by this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
- * The entry associated by |key| does not exist.
+ * The data associated by |key| does not exist.
*/
-int nghttp2_map_remove(nghttp2_map *map, key_type key);
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
+
+/*
+ * Removes all entries from |map|.
+ */
+void nghttp2_map_clear(nghttp2_map *map);
/*
* Returns the number of items stored in the map |map|.
@@ -124,21 +121,22 @@ int nghttp2_map_remove(nghttp2_map *map, key_type key);
size_t nghttp2_map_size(nghttp2_map *map);
/*
- * Applies the function |func| to each entry in the |map| with the
+ * Applies the function |func| to each data in the |map| with the
* optional user supplied pointer |ptr|.
*
* If the |func| returns 0, this function calls the |func| with the
- * next entry. If the |func| returns nonzero, it will not call the
+ * next data. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns.
*
- * Don't use this function to free each entry. Use
+ * Don't use this function to free each data. Use
* nghttp2_map_each_free() instead.
*/
-int nghttp2_map_each(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
+void nghttp2_map_print_distance(nghttp2_map *map);
+
#endif /* NGHTTP2_MAP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_net.h b/Utilities/cmnghttp2/lib/nghttp2_net.h
index 95ffee7..521f981 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_net.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_net.h
@@ -42,7 +42,7 @@
#if defined(WIN32)
/* Windows requires ws2_32 library for ntonl family functions. We
define inline functions for those function so that we don't have
- dependeny on that lib. */
+ dependency on that lib. */
# ifdef _MSC_VER
# define STIN static __inline
@@ -53,7 +53,7 @@
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostlong >> 24;
+ *p++ = (unsigned char)(hostlong >> 24);
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
@@ -63,7 +63,7 @@ STIN uint32_t htonl(uint32_t hostlong) {
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostshort >> 8;
+ *p++ = (unsigned char)(hostshort >> 8);
*p = hostshort & 0xffu;
return res;
}
@@ -71,9 +71,9 @@ STIN uint16_t htons(uint16_t hostshort) {
STIN uint32_t ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
- res = *p++ << 24;
- res += *p++ << 16;
- res += *p++ << 8;
+ res = (uint32_t)(*p++ << 24);
+ res += (uint32_t)(*p++ << 16);
+ res += (uint32_t)(*p++ << 8);
res += *p;
return res;
}
@@ -81,7 +81,7 @@ STIN uint32_t ntohl(uint32_t netlong) {
STIN uint16_t ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
- res = *p++ << 8;
+ res = (uint16_t)(*p++ << 8);
res += *p;
return res;
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.c b/Utilities/cmnghttp2/lib/nghttp2_option.c
index e53f22d..ee0cd0f 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.c
@@ -90,6 +90,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
return;
+ case NGHTTP2_PRIORITY_UPDATE:
+ option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
+ option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE;
+ return;
default:
return;
}
@@ -121,3 +125,21 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
option->max_outbound_ack = val;
}
+
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
+ option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
+ option->max_settings = val;
+}
+
+void nghttp2_option_set_server_fallback_rfc7540_priorities(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ option->server_fallback_rfc7540_priorities = val;
+}
+
+void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |=
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ option->no_rfc9113_leading_and_trailing_ws_validation = val;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.h b/Utilities/cmnghttp2/lib/nghttp2_option.h
index 1f740aa..b228a07 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.h
@@ -67,6 +67,9 @@ typedef enum {
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
+ NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
} nghttp2_option_flag;
/**
@@ -86,6 +89,10 @@ struct nghttp2_option {
*/
size_t max_outbound_ack;
/**
+ * NGHTTP2_OPT_MAX_SETTINGS
+ */
+ size_t max_settings;
+ /**
* Bitwise OR of nghttp2_option_flag to determine that which fields
* are specified.
*/
@@ -123,6 +130,14 @@ struct nghttp2_option {
*/
int no_closed_streams;
/**
+ * NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES
+ */
+ int server_fallback_rfc7540_priorities;
+ /**
+ * NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION
+ */
+ int no_rfc9113_leading_and_trailing_ws_validation;
+ /**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
uint8_t user_recv_ext_types[32];
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
index f651c80..2a3041d 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
@@ -89,6 +89,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
case NGHTTP2_ORIGIN:
nghttp2_frame_origin_free(&frame->ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ break;
default:
assert(0);
break;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
index b5f503a..bd4611b 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
@@ -111,7 +111,7 @@ struct nghttp2_outbound_item {
to this structure to avoid frequent memory allocation. */
nghttp2_ext_frame_payload ext_frame_payload;
nghttp2_aux_data aux_data;
- /* The priority used in priority comparion. Smaller is served
+ /* The priority used in priority comparison. Smaller is served
earlier. For PING, SETTINGS and non-DATA frames (excluding
response HEADERS frame) have dedicated cycle value defined above.
For DATA frame, cycle is computed by taking into account of
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.c b/Utilities/cmnghttp2/lib/nghttp2_pq.c
index bebccc7..64353ac 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.c
@@ -29,13 +29,12 @@
#include "nghttp2_helper.h"
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
pq->mem = mem;
pq->capacity = 0;
pq->q = NULL;
pq->length = 0;
pq->less = less;
- return 0;
}
void nghttp2_pq_free(nghttp2_pq *pq) {
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.h b/Utilities/cmnghttp2/lib/nghttp2_pq.h
index 2d7b702..c8d90ef 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.h
@@ -55,14 +55,8 @@ typedef struct {
/*
* Initializes priority queue |pq| with compare function |cmp|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
*/
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are
@@ -114,7 +108,7 @@ typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
/*
- * Applys |fun| to each item in |pq|. The |arg| is passed as arg
+ * Applies |fun| to each item in |pq|. The |arg| is passed as arg
* parameter to callback function. This function must not change the
* ordering key. If the return value from callback is nonzero, this
* function returns 1 immediately without iterating remaining items.
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.c b/Utilities/cmnghttp2/lib/nghttp2_session.c
index 9df3d6f..93f3f07 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.c
@@ -36,6 +36,7 @@
#include "nghttp2_option.h"
#include "nghttp2_http.h"
#include "nghttp2_pq.h"
+#include "nghttp2_extpri.h"
#include "nghttp2_debug.h"
/*
@@ -143,6 +144,11 @@ static int session_detect_idle_stream(nghttp2_session *session,
return 0;
}
+static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) {
+ return session->pending_no_rfc7540_priorities == 1 &&
+ !session->fallback_rfc7540_priorities;
+}
+
static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) {
return (ext_types[type / 8] & (1 << (type & 0x7))) > 0;
}
@@ -354,6 +360,14 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
}
nghttp2_frame_origin_free(&iframe->frame.ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ break;
+ }
+ /* Do not call nghttp2_frame_priority_update_free, because all
+ fields point to sbuf. */
+ break;
}
}
@@ -385,6 +399,7 @@ static void init_settings(nghttp2_settings_storage *settings) {
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
settings->max_header_list_size = UINT32_MAX;
+ settings->no_rfc7540_priorities = UINT32_MAX;
}
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
@@ -398,6 +413,21 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
aob->state = NGHTTP2_OB_POP_ITEM;
}
+#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX)
+
+static int stream_less(const void *lhsx, const void *rhsx) {
+ const nghttp2_stream *lhs, *rhs;
+
+ lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
+ rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
+
+ if (lhs->cycle == rhs->cycle) {
+ return lhs->seq < rhs->seq;
+ }
+
+ return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP;
+}
+
int nghttp2_enable_strict_preface = 1;
static int session_new(nghttp2_session **session_ptr,
@@ -408,6 +438,7 @@ static int session_new(nghttp2_session **session_ptr,
size_t nbuffer;
size_t max_deflate_dynamic_table_size =
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
+ size_t i;
if (mem == NULL) {
mem = nghttp2_mem_default();
@@ -442,6 +473,7 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->pending_local_max_concurrent_stream =
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
(*session_ptr)->pending_enable_push = 1;
+ (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
if (server) {
(*session_ptr)->server = 1;
@@ -458,6 +490,7 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
(*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
+ (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
if (option) {
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -521,6 +554,25 @@ static int session_new(nghttp2_session **session_ptr,
if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
(*session_ptr)->max_outbound_ack = option->max_outbound_ack;
}
+
+ if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
+ option->max_settings) {
+ (*session_ptr)->max_settings = option->max_settings;
+ }
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) &&
+ option->server_fallback_rfc7540_priorities) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ }
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ option->no_rfc9113_leading_and_trailing_ws_validation) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -578,6 +630,10 @@ static int session_new(nghttp2_session **session_ptr,
}
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem);
+ }
+
return 0;
fail_aob_framebuf:
@@ -660,7 +716,7 @@ int nghttp2_session_server_new3(nghttp2_session **session_ptr,
return 0;
}
-static int free_streams(nghttp2_map_entry *entry, void *ptr) {
+static int free_streams(void *entry, void *ptr) {
nghttp2_session *session;
nghttp2_stream *stream;
nghttp2_outbound_item *item;
@@ -729,6 +785,7 @@ static void inflight_settings_del(nghttp2_inflight_settings *settings,
void nghttp2_session_del(nghttp2_session *session) {
nghttp2_mem *mem;
nghttp2_inflight_settings *settings;
+ size_t i;
if (session == NULL) {
return;
@@ -742,6 +799,9 @@ void nghttp2_session_del(nghttp2_session *session) {
settings = next;
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_free(&session->sched[i].ob_data);
+ }
nghttp2_stream_free(&session->root);
/* Have to free streams first, so that we can check
@@ -769,6 +829,8 @@ int nghttp2_session_reprioritize_stream(
nghttp2_priority_spec pri_spec_default;
const nghttp2_priority_spec *pri_spec = pri_spec_in;
+ assert((!session->server && session->pending_no_rfc7540_priorities != 1) ||
+ (session->server && !session_no_rfc7540_pri_no_fallback(session)));
assert(pri_spec->stream_id != stream->stream_id);
if (!nghttp2_stream_in_dep_tree(stream)) {
@@ -836,6 +898,214 @@ int nghttp2_session_reprioritize_stream(
return 0;
}
+static uint64_t pq_get_first_cycle(nghttp2_pq *pq) {
+ nghttp2_stream *stream;
+
+ if (nghttp2_pq_empty(pq)) {
+ return 0;
+ }
+
+ stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry);
+ return stream->cycle;
+}
+
+static int session_ob_data_push(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ int rv;
+ uint32_t urgency;
+ int inc;
+ nghttp2_pq *pq;
+
+ assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+ assert(stream->queued == 0);
+
+ urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ inc = nghttp2_extpri_uint8_inc(stream->extpri);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ stream->cycle = pq_get_first_cycle(pq);
+ if (inc) {
+ stream->cycle += stream->last_writelen;
+ }
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+ if (rv != 0) {
+ return rv;
+ }
+
+ stream->queued = 1;
+
+ return 0;
+}
+
+static int session_ob_data_remove(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ uint32_t urgency;
+
+ assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+ assert(stream->queued == 1);
+
+ urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
+
+ stream->queued = 0;
+
+ return 0;
+}
+
+static int session_attach_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ nghttp2_outbound_item *item) {
+ int rv;
+
+ rv = nghttp2_stream_attach_item(stream, item);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static int session_detach_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ int rv;
+
+ rv = nghttp2_stream_detach_item(stream);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ !stream->queued) {
+ return 0;
+ }
+
+ return session_ob_data_remove(session, stream);
+}
+
+static int session_defer_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream, uint8_t flags) {
+ int rv;
+
+ rv = nghttp2_stream_defer_item(stream, flags);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ !stream->queued) {
+ return 0;
+ }
+
+ return session_ob_data_remove(session, stream);
+}
+
+static int session_resume_deferred_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t flags) {
+ int rv;
+
+ rv = nghttp2_stream_resume_deferred_item(stream, flags);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static nghttp2_outbound_item *
+session_sched_get_next_outbound_item(nghttp2_session *session) {
+ size_t i;
+ nghttp2_pq_entry *ent;
+ nghttp2_stream *stream;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ ent = nghttp2_pq_top(&session->sched[i].ob_data);
+ if (!ent) {
+ continue;
+ }
+
+ stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
+ return stream->item;
+ }
+
+ return NULL;
+}
+
+static int session_sched_empty(nghttp2_session *session) {
+ size_t i;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ if (!nghttp2_pq_empty(&session->sched[i].ob_data)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void session_sched_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ nghttp2_pq *pq;
+ uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ int inc = nghttp2_extpri_uint8_inc(stream->extpri);
+ uint64_t penalty = (uint64_t)stream->last_writelen;
+ int rv;
+
+ (void)rv;
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ if (!inc || nghttp2_pq_size(pq) == 1) {
+ return;
+ }
+
+ nghttp2_pq_remove(pq, &stream->pq_entry);
+
+ stream->cycle += penalty;
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+
+ assert(0 == rv);
+}
+
+static int session_update_stream_priority(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t u8extpri) {
+ if (stream->extpri == u8extpri) {
+ return 0;
+ }
+
+ if (stream->queued) {
+ session_ob_data_remove(session, stream);
+
+ stream->extpri = u8extpri;
+
+ return session_ob_data_push(session, stream);
+ }
+
+ stream->extpri = u8extpri;
+
+ return 0;
+}
+
int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item) {
/* TODO Return error if stream is not found for the frame requiring
@@ -857,7 +1127,7 @@ int nghttp2_session_add_item(nghttp2_session *session,
return NGHTTP2_ERR_DATA_EXIST;
}
- rv = nghttp2_stream_attach_item(stream, item);
+ rv = session_attach_stream_item(session, stream, item);
if (rv != 0) {
return rv;
@@ -953,6 +1223,18 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
return 0;
}
+ /* Sending RST_STREAM to an idle stream is subject to protocol
+ violation. Historically, nghttp2 allows this. In order not to
+ disrupt the existing applications, we don't error out this case
+ and simply ignore it. */
+ if (nghttp2_session_is_my_stream_id(session, stream_id)) {
+ if ((uint32_t)stream_id >= session->next_stream_id) {
+ return 0;
+ }
+ } else if (session->last_recv_stream_id < stream_id) {
+ return 0;
+ }
+
/* Cancel pending request HEADERS in ob_syn if this RST_STREAM
refers to that stream. */
if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) &&
@@ -963,8 +1245,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame;
assert(headers_frame->hd.type == NGHTTP2_HEADERS);
- if (headers_frame->hd.stream_id <= stream_id &&
- (uint32_t)stream_id < session->next_stream_id) {
+ if (headers_frame->hd.stream_id <= stream_id) {
for (item = session->ob_syn.head; item; item = item->qnext) {
aux_data = &item->aux_data.headers;
@@ -1022,13 +1303,27 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
mem = &session->mem;
stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (session->opt_flags &
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
+
if (stream) {
assert(stream->state == NGHTTP2_STREAM_IDLE);
- assert(nghttp2_stream_in_dep_tree(stream));
- nghttp2_session_detach_idle_stream(session, stream);
- rv = nghttp2_stream_dep_remove(stream);
- if (rv != 0) {
- return NULL;
+ assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ nghttp2_stream_in_dep_tree(stream));
+
+ if (nghttp2_stream_in_dep_tree(stream)) {
+ assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
+ nghttp2_session_detach_idle_stream(session, stream);
+ rv = nghttp2_stream_dep_remove(stream);
+ if (rv != 0) {
+ return NULL;
+ }
+
+ if (session_no_rfc7540_pri_no_fallback(session)) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
}
} else {
stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream));
@@ -1039,7 +1334,21 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
stream_alloc = 1;
}
- if (pri_spec->stream_id != 0) {
+ if (session_no_rfc7540_pri_no_fallback(session) ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ /* For client which has not received server
+ SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal
+ opportunistically. */
+ if (session->server ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ nghttp2_priority_spec_default_init(&pri_spec_default);
+ pri_spec = &pri_spec_default;
+ }
+
+ if (session->pending_no_rfc7540_priorities == 1) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
+ } else if (pri_spec->stream_id != 0) {
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
if (!dep_stream &&
@@ -1085,7 +1394,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
(int32_t)session->local_settings.initial_window_size,
stream_user_data, mem);
- rv = nghttp2_map_insert(&session->streams, &stream->map_entry);
+ if (session_no_rfc7540_pri_no_fallback(session)) {
+ stream->seq = session->stream_seq++;
+ }
+
+ rv = nghttp2_map_insert(&session->streams, stream_id, stream);
if (rv != 0) {
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
@@ -1124,6 +1437,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
}
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return stream;
+ }
+
if (pri_spec->stream_id == 0) {
dep_stream = &session->root;
}
@@ -1163,7 +1480,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
item = stream->item;
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (rv != 0) {
return rv;
@@ -1213,6 +1530,10 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
/* Closes both directions just in case they are not closed yet */
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return nghttp2_session_destroy_stream(session, stream);
+ }
+
if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 &&
session->server && !is_my_stream_id &&
nghttp2_stream_in_dep_tree(stream)) {
@@ -1767,6 +2088,28 @@ static int session_predicate_origin_send(nghttp2_session *session) {
return 0;
}
+static int session_predicate_priority_update_send(nghttp2_session *session,
+ int32_t stream_id) {
+ nghttp2_stream *stream;
+
+ if (session_is_closing(session)) {
+ return NGHTTP2_ERR_SESSION_CLOSING;
+ }
+
+ stream = nghttp2_session_get_stream(session, stream_id);
+ if (stream == NULL) {
+ return 0;
+ }
+ if (stream->state == NGHTTP2_STREAM_CLOSING) {
+ return NGHTTP2_ERR_STREAM_CLOSING;
+ }
+ if (stream->shut_flags & NGHTTP2_SHUT_RD) {
+ return NGHTTP2_ERR_INVALID_STREAM_STATE;
+ }
+
+ return 0;
+}
+
/* Take into account settings max frame size and both connection-level
flow control here */
static ssize_t
@@ -1996,7 +2339,7 @@ static int session_prep_frame(nghttp2_session *session,
if (stream) {
int rv2;
- rv2 = nghttp2_stream_detach_item(stream);
+ rv2 = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv2)) {
return rv2;
@@ -2015,7 +2358,7 @@ static int session_prep_frame(nghttp2_session *session,
queue when session->remote_window_size > 0 */
assert(session->remote_window_size > 0);
- rv = nghttp2_stream_defer_item(stream,
+ rv = session_defer_stream_item(session, stream,
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
@@ -2034,7 +2377,8 @@ static int session_prep_frame(nghttp2_session *session,
return rv;
}
if (rv == NGHTTP2_ERR_DEFERRED) {
- rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
+ rv = session_defer_stream_item(session, stream,
+ NGHTTP2_STREAM_FLAG_DEFERRED_USER);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -2045,7 +2389,7 @@ static int session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_DEFERRED;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -2061,7 +2405,7 @@ static int session_prep_frame(nghttp2_session *session,
if (rv != 0) {
int rv2;
- rv2 = nghttp2_stream_detach_item(stream);
+ rv2 = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv2)) {
return rv2;
@@ -2311,6 +2655,18 @@ static int session_prep_frame(nghttp2_session *session,
}
return 0;
+ case NGHTTP2_PRIORITY_UPDATE: {
+ nghttp2_ext_priority_update *priority_update = frame->ext.payload;
+ rv = session_predicate_priority_update_send(session,
+ priority_update->stream_id);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext);
+
+ return 0;
+ }
default:
/* Unreachable here */
assert(0);
@@ -2322,6 +2678,8 @@ static int session_prep_frame(nghttp2_session *session,
nghttp2_outbound_item *
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
+ nghttp2_outbound_item *item;
+
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
return nghttp2_outbound_queue_top(&session->ob_urgent);
}
@@ -2337,7 +2695,12 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2371,7 +2734,12 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2407,7 +2775,7 @@ static int session_call_on_frame_send(nghttp2_session *session,
return 0;
}
-static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) {
+static int find_stream_on_goaway_func(void *entry, void *ptr) {
nghttp2_close_stream_on_goaway_arg *arg;
nghttp2_stream *stream;
@@ -2481,10 +2849,20 @@ static int session_close_stream_on_goaway(nghttp2_session *session,
return 0;
}
-static void reschedule_stream(nghttp2_stream *stream) {
+static void session_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
stream->last_writelen = stream->item->frame.hd.length;
- nghttp2_stream_reschedule(stream);
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ nghttp2_stream_reschedule(stream);
+ return;
+ }
+
+ if (!session->server) {
+ return;
+ }
+
+ session_sched_reschedule_stream(session, stream);
}
static int session_update_stream_consumed_size(nghttp2_session *session,
@@ -2494,14 +2872,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
static int session_update_connection_consumed_size(nghttp2_session *session,
size_t delta_size);
-static int session_update_recv_connection_window_size(nghttp2_session *session,
- size_t delta_size);
-
-static int session_update_recv_stream_window_size(nghttp2_session *session,
- nghttp2_stream *stream,
- size_t delta_size,
- int send_window_update);
-
/*
* Called after a frame is sent. This function runs
* on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2541,7 +2911,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
if (stream && aux_data->eof) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -2666,9 +3036,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
}
case NGHTTP2_PRIORITY:
- if (session->server) {
+ if (session->server || session->pending_no_rfc7540_priorities == 1) {
return 0;
- ;
}
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
@@ -2735,7 +3104,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_connection_consumed_size(session, 0);
} else {
- rv = session_update_recv_connection_window_size(session, 0);
+ rv = nghttp2_session_update_recv_connection_window_size(session, 0);
}
if (nghttp2_is_fatal(rv)) {
@@ -2761,7 +3130,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_stream_consumed_size(session, stream, 0);
} else {
- rv = session_update_recv_stream_window_size(session, stream, 0, 1);
+ rv =
+ nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1);
}
if (nghttp2_is_fatal(rv)) {
@@ -2842,7 +3212,7 @@ static int session_after_frame_sent2(nghttp2_session *session) {
further data. */
if (nghttp2_session_predicate_data_send(session, stream) != 0) {
if (stream) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -3140,7 +3510,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -3720,6 +4090,21 @@ static int session_end_stream_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream) {
int rv;
+
+ assert(frame->hd.type == NGHTTP2_HEADERS);
+
+ if (session->server && session_enforce_http_messaging(session) &&
+ frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) &&
+ (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) {
+ rv = session_update_stream_priority(session, stream, stream->http_extpri);
+ if (rv != 0) {
+ assert(nghttp2_is_fatal(rv));
+ return rv;
+ }
+ }
+
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
return 0;
}
@@ -4081,6 +4466,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
int rv;
nghttp2_stream *stream;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
if (frame->hd.stream_id == 0) {
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PRIORITY: stream_id == 0");
@@ -4138,6 +4525,8 @@ static int session_process_priority_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
return nghttp2_session_on_priority_received(session, frame);
@@ -4184,8 +4573,7 @@ static int session_process_rst_stream_frame(nghttp2_session *session) {
return nghttp2_session_on_rst_stream_received(session, frame);
}
-static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
- void *ptr) {
+static int update_remote_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -4205,8 +4593,8 @@ static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4238,8 +4626,7 @@ session_update_remote_initial_window_size(nghttp2_session *session,
update_remote_initial_window_size_func, &arg);
}
-static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
- void *ptr) {
+static int update_local_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -4251,9 +4638,16 @@ static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
NGHTTP2_FLOW_CONTROL_ERROR);
}
- if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) &&
- stream->window_update_queued == 0 &&
- nghttp2_should_send_window_update(stream->local_window_size,
+
+ if (stream->window_update_queued) {
+ return 0;
+ }
+
+ if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
+ return session_update_stream_consumed_size(arg->session, stream, 0);
+ }
+
+ if (nghttp2_should_send_window_update(stream->local_window_size,
stream->recv_window_size)) {
rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE,
@@ -4374,6 +4768,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
session->local_settings.enable_connect_protocol = iv[i].value;
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ session->local_settings.no_rfc7540_priorities = iv[i].value;
+ break;
}
}
@@ -4533,6 +4930,34 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
session->remote_settings.enable_connect_protocol = entry->value;
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+
+ if (entry->value != 0 && entry->value != 1) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES");
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX &&
+ session->remote_settings.no_rfc7540_priorities != entry->value) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed");
+ }
+
+ session->remote_settings.no_rfc7540_priorities = entry->value;
+
+ break;
+ }
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) {
+ session->remote_settings.no_rfc7540_priorities = 0;
+
+ if (session->server && session->pending_no_rfc7540_priorities &&
+ (session->opt_flags &
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) {
+ session->fallback_rfc7540_priorities = 1;
}
}
@@ -4818,8 +5243,8 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4890,6 +5315,80 @@ int nghttp2_session_on_origin_received(nghttp2_session *session,
return session_call_on_frame_received(session, frame);
}
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame) {
+ nghttp2_ext_priority_update *priority_update;
+ nghttp2_stream *stream;
+ nghttp2_priority_spec pri_spec;
+ nghttp2_extpri extpri;
+ int rv;
+
+ assert(session->server);
+
+ priority_update = frame->ext.payload;
+
+ if (frame->hd.stream_id != 0) {
+ return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: stream_id == 0");
+ }
+
+ if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) {
+ if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: prioritizing idle push is not allowed");
+ }
+
+ /* TODO Ignore priority signal to a push stream for now */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id);
+ if (stream) {
+ /* Stream already exists. */
+ if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) {
+ return session_call_on_frame_received(session, frame);
+ }
+ } else if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ if (session->num_idle_streams + session->num_incoming_streams >=
+ session->local_settings.max_concurrent_streams) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: max concurrent streams exceeded");
+ }
+
+ nghttp2_priority_spec_default_init(&pri_spec);
+ stream = nghttp2_session_open_stream(session, priority_update->stream_id,
+ NGHTTP2_FLAG_NONE, &pri_spec,
+ NGHTTP2_STREAM_IDLE, NULL);
+ if (!stream) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+ } else {
+ return session_call_on_frame_received(session, frame);
+ }
+
+ extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
+ extpri.inc = 0;
+
+ rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value,
+ priority_update->field_value_len);
+ if (rv != 0) {
+ /* Just ignore field_value if it cannot be parsed. */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ rv = session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+ if (rv != 0) {
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ }
+
+ return session_call_on_frame_received(session, frame);
+}
+
static int session_process_altsvc_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
@@ -4924,6 +5423,16 @@ static int session_process_origin_frame(nghttp2_session *session) {
return nghttp2_session_on_origin_received(session, frame);
}
+static int session_process_priority_update_frame(nghttp2_session *session) {
+ nghttp2_inbound_frame *iframe = &session->iframe;
+ nghttp2_frame *frame = &iframe->frame;
+
+ nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos,
+ nghttp2_buf_len(&iframe->sbuf));
+
+ return nghttp2_session_on_priority_update_received(session, frame);
+}
+
static int session_process_extension_frame(nghttp2_session *session) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
@@ -5019,22 +5528,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
return 0;
}
-/*
- * Accumulates received bytes |delta_size| for stream-level flow
- * control and decides whether to send WINDOW_UPDATE to that stream.
- * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
- * be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- */
-static int session_update_recv_stream_window_size(nghttp2_session *session,
- nghttp2_stream *stream,
- size_t delta_size,
- int send_window_update) {
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+ nghttp2_stream *stream,
+ size_t delta_size,
+ int send_window_update) {
int rv;
rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
stream->local_window_size);
@@ -5063,20 +5560,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
return 0;
}
-/*
- * Accumulates received bytes |delta_size| for connection-level flow
- * control and decides whether to send WINDOW_UPDATE to the
- * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
- * WINDOW_UPDATE will not be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- */
-static int session_update_recv_connection_window_size(nghttp2_session *session,
- size_t delta_size) {
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+ size_t delta_size) {
int rv;
rv = adjust_recv_window_size(&session->recv_window_size, delta_size,
session->local_window_size);
@@ -5285,6 +5770,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
break;
default:
DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
@@ -5357,7 +5843,7 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
/*
* This function returns the effective payload length in the data of
- * length |readlen| when the remaning payload is |payloadleft|. The
+ * length |readlen| when the remaining payload is |payloadleft|. The
* |payloadleft| does not include |readlen|. If padding was started
* strictly before this data chunk, this function returns -1.
*/
@@ -5378,9 +5864,11 @@ static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
return (ssize_t)(readlen);
}
+static const uint8_t static_in[] = {0};
+
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
size_t inlen) {
- const uint8_t *first = in, *last = in + inlen;
+ const uint8_t *first, *last;
nghttp2_inbound_frame *iframe = &session->iframe;
size_t readlen;
ssize_t padlen;
@@ -5391,6 +5879,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
size_t pri_fieldlen;
nghttp2_mem *mem;
+ if (in == NULL) {
+ assert(inlen == 0);
+ in = static_in;
+ }
+
+ first = in;
+ last = in + inlen;
+
DEBUGF("recv: connection recv_window_size=%d, local_window=%d\n",
session->recv_window_size, session->local_window_size);
@@ -5678,6 +6174,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
}
+ /* Check the settings flood counter early to be safe */
+ if (session->obq_flood_counter_ >= session->max_outbound_ack &&
+ !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
+ return NGHTTP2_ERR_FLOODED;
+ }
+
iframe->state = NGHTTP2_IB_READ_SETTINGS;
if (iframe->payloadleft) {
@@ -5688,6 +6190,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->max_niv =
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
+ if (iframe->max_niv - 1 > session->max_settings) {
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_ENHANCE_YOUR_CALM,
+ "SETTINGS: too many setting entries");
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ return (ssize_t)inlen;
+ }
+
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
iframe->max_niv);
@@ -5873,6 +6385,49 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD;
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ DEBUGF("recv: PRIORITY_UPDATE\n");
+
+ iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
+ iframe->frame.ext.payload =
+ &iframe->ext_frame_payload.priority_update;
+
+ if (!session->server) {
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_PROTOCOL_ERROR,
+ "PRIORITY_UPDATE is received from server");
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ return (ssize_t)inlen;
+ }
+
+ if (iframe->payloadleft < 4) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
+ break;
+ }
+
+ if (!session_no_rfc7540_pri_no_fallback(session) ||
+ iframe->payloadleft > sizeof(iframe->raw_sbuf)) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ busy = 1;
+
+ iframe->state = NGHTTP2_IB_READ_NBYTE;
+ inbound_frame_set_mark(iframe, iframe->payloadleft);
+
+ break;
default:
busy = 1;
@@ -5978,13 +6533,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
case NGHTTP2_PRIORITY:
- rv = session_process_priority_frame(session);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ if (!session_no_rfc7540_pri_no_fallback(session) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
+ rv = session_process_priority_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (ssize_t)inlen;
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return (ssize_t)inlen;
+ }
}
session_inbound_frame_reset(session);
@@ -6141,6 +6699,18 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD;
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ DEBUGF("recv: prioritized_stream_id=%d\n",
+ nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK);
+
+ rv = session_process_priority_update_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ session_inbound_frame_reset(session);
+
+ break;
}
default:
/* This is unknown frame */
@@ -6420,8 +6990,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
/* CONTINUATION won't bear NGHTTP2_PADDED flag */
- iframe->frame.hd.flags = (uint8_t)(
- iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
+ iframe->frame.hd.flags =
+ (uint8_t)(iframe->frame.hd.flags |
+ (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
iframe->frame.hd.length += cont_hd.length;
busy = 1;
@@ -6454,7 +7025,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
}
/* Pad Length field is subject to flow control */
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6477,7 +7048,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) {
- rv = session_update_recv_stream_window_size(
+ rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6524,7 +7095,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
ssize_t data_readlen;
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session,
+ readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6533,7 +7105,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return (ssize_t)inlen;
}
- rv = session_update_recv_stream_window_size(
+ rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6634,7 +7206,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
/* Update connection-level flow control window for ignored
DATA frame too */
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session,
+ readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6850,7 +7423,8 @@ int nghttp2_session_want_write(nghttp2_session *session) {
*/
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
nghttp2_outbound_queue_top(&session->ob_reg) ||
- (!nghttp2_pq_empty(&session->root.obq) &&
+ ((!nghttp2_pq_empty(&session->root.obq) ||
+ !session_sched_empty(session)) &&
session->remote_window_size > 0) ||
(nghttp2_outbound_queue_top(&session->ob_syn) &&
!session_is_outgoing_concurrent_streams_max(session));
@@ -7003,6 +7577,7 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
int rv;
nghttp2_mem *mem;
nghttp2_inflight_settings *inflight_settings = NULL;
+ uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities;
mem = &session->mem;
@@ -7020,6 +7595,21 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
+ for (i = 0; i < niv; ++i) {
+ if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) {
+ continue;
+ }
+
+ if (no_rfc7540_pri == UINT8_MAX) {
+ no_rfc7540_pri = (uint8_t)iv[i].value;
+ continue;
+ }
+
+ if (iv[i].value != (uint32_t)no_rfc7540_pri) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ }
+
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
return NGHTTP2_ERR_NOMEM;
@@ -7094,6 +7684,12 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
}
}
+ if (no_rfc7540_pri == UINT8_MAX) {
+ session->pending_no_rfc7540_priorities = 0;
+ } else {
+ session->pending_no_rfc7540_priorities = no_rfc7540_pri;
+ }
+
return 0;
}
@@ -7222,7 +7818,7 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
return rv;
}
- reschedule_stream(stream);
+ session_reschedule_stream(session, stream);
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
@@ -7296,7 +7892,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
- rv = nghttp2_stream_resume_deferred_item(stream,
+ rv = session_resume_deferred_stream_item(session, stream,
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
if (nghttp2_is_fatal(rv)) {
@@ -7404,6 +8000,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
return session->remote_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->remote_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->remote_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7427,6 +8025,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
return session->local_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->local_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->local_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7454,6 +8054,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
+ /* SETTINGS frame contains too many settings */
+ if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH >
+ session->max_settings) {
+ return NGHTTP2_ERR_TOO_MANY_SETTINGS;
+ }
rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
settings_payloadlen, mem);
if (rv != 0) {
@@ -7705,6 +8310,10 @@ int nghttp2_session_change_stream_priority(
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -7737,6 +8346,10 @@ int nghttp2_session_create_idle_stream(nghttp2_session *session,
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id ||
!session_detect_idle_stream(session, stream_id)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
@@ -7778,3 +8391,38 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
session->user_data = user_data;
}
+
+int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id,
+ const nghttp2_extpri *extpri_in, int ignore_client_signal) {
+ nghttp2_stream *stream;
+ nghttp2_extpri extpri = *extpri_in;
+
+ if (!session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->pending_no_rfc7540_priorities != 1) {
+ return 0;
+ }
+
+ if (stream_id == 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (!stream) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) {
+ extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW;
+ }
+
+ if (ignore_client_signal) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES;
+ }
+
+ return session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.h b/Utilities/cmnghttp2/lib/nghttp2_session.h
index 90ead9c..34d2d58 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.h
@@ -52,7 +52,9 @@ typedef enum {
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
- NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
+ NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
} nghttp2_optmask;
/*
@@ -62,7 +64,8 @@ typedef enum {
typedef enum {
NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
- NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
+ NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
} nghttp2_typemask;
typedef enum {
@@ -151,10 +154,8 @@ typedef struct {
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
- /* Small buffer. Currently the largest contiguous chunk to buffer
- is frame header. We buffer part of payload, but they are smaller
- than frame header. */
- uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+ /* Small fixed sized buffer. */
+ uint8_t raw_sbuf[32];
} nghttp2_inbound_frame;
typedef struct {
@@ -165,6 +166,7 @@ typedef struct {
uint32_t max_frame_size;
uint32_t max_header_list_size;
uint32_t enable_connect_protocol;
+ uint32_t no_rfc7540_priorities;
} nghttp2_settings_storage;
typedef enum {
@@ -202,6 +204,12 @@ struct nghttp2_session {
response) frame, which are subject to
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
nghttp2_outbound_queue ob_syn;
+ /* Queues for DATA frames which is used when
+ SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC
+ 9218 extensible prioritization scheme. */
+ struct {
+ nghttp2_pq ob_data;
+ } sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater;
@@ -227,6 +235,9 @@ struct nghttp2_session {
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
considered as in-flight. */
nghttp2_inflight_settings *inflight_settings_head;
+ /* Sequential number across all streams to process streams in
+ FIFO. */
+ uint64_t stream_seq;
/* The number of outgoing streams. This will be capped by
remote_settings.max_concurrent_streams. */
size_t num_outgoing_streams;
@@ -267,6 +278,8 @@ struct nghttp2_session {
/* The maximum length of header block to send. Calculated by the
same way as nghttp2_hd_deflate_bound() does. */
size_t max_send_header_block_length;
+ /* The maximum number of settings accepted per SETTINGS frame. */
+ size_t max_settings;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The last stream ID this session initiated. For client session,
@@ -326,6 +339,11 @@ struct nghttp2_session {
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
accept :protocol header field before SETTINGS_ACK is received. */
uint8_t pending_enable_connect_protocol;
+ /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
+ effective before it is acknowledged. */
+ uint8_t pending_no_rfc7540_priorities;
+ /* Turn on fallback to RFC 7540 priorities; for server use only. */
+ uint8_t fallback_rfc7540_priorities;
/* Nonzero if the session is server side. */
uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -406,7 +424,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
uint32_t error_code);
/*
- * Adds PING frame. This is a convenient functin built on top of
+ * Adds PING frame. This is a convenient function built on top of
* nghttp2_session_add_frame() to add PING easily.
*
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
@@ -772,6 +790,19 @@ int nghttp2_session_on_origin_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
+ * Called when PRIORITY_UPDATE is received, assuming |frame| is
+ * properly initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ * The callback function failed.
+ */
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame);
+
+/*
* Called when DATA is received, assuming |frame| is properly
* initialized.
*
@@ -898,4 +929,36 @@ int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
uint32_t error_code,
const char *reason);
+/*
+ * Accumulates received bytes |delta_size| for connection-level flow
+ * control and decides whether to send WINDOW_UPDATE to the
+ * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
+ * WINDOW_UPDATE will not be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ * Out of memory.
+ */
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+ size_t delta_size);
+
+/*
+ * Accumulates received bytes |delta_size| for stream-level flow
+ * control and decides whether to send WINDOW_UPDATE to that stream.
+ * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
+ * be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ * Out of memory.
+ */
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+ nghttp2_stream *stream,
+ size_t delta_size,
+ int send_window_update);
+
#endif /* NGHTTP2_SESSION_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.c b/Utilities/cmnghttp2/lib/nghttp2_stream.c
index dc3a6b1..b3614a0 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.c
@@ -33,7 +33,7 @@
#include "nghttp2_frame.h"
/* Maximum distance between any two stream's cycle in the same
- prirority queue. Imagine stream A's cycle is A, and stream B's
+ priority queue. Imagine stream A's cycle is A, and stream B's
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
may get overflow. Because of how we calculate the next cycle
value, if B - A is less than or equals to
@@ -62,7 +62,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data, nghttp2_mem *mem) {
- nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
nghttp2_pq_init(&stream->obq, stream_less, mem);
stream->stream_id = stream_id;
@@ -101,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->descendant_next_seq = 0;
stream->seq = 0;
stream->last_writelen = 0;
+
+ stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
}
void nghttp2_stream_free(nghttp2_stream *stream) {
@@ -485,6 +486,10 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
stream->item = item;
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
rv = stream_update_dep_on_attach_item(stream);
if (rv != 0) {
/* This may relave stream->queued == 1, but stream->item == NULL.
@@ -504,6 +509,10 @@ int nghttp2_stream_detach_item(nghttp2_stream *stream) {
stream->item = NULL;
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_detach_item(stream);
}
@@ -515,6 +524,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
stream->flags |= flags;
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_detach_item(stream);
}
@@ -530,6 +543,10 @@ int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
return 0;
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_attach_item(stream);
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.h b/Utilities/cmnghttp2/lib/nghttp2_stream.h
index a1b807d..7a8e4c6 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.h
@@ -90,8 +90,15 @@ typedef enum {
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
- NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
-
+ NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
+ /* Indicates that this stream is not subject to RFC7540
+ priorities scheme. */
+ NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
+ /* Ignore client RFC 9218 priority signal. */
+ NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
+ /* Indicates that RFC 9113 leading and trailing white spaces
+ validation against a field value is not performed. */
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40,
} nghttp2_stream_flag;
/* HTTP related flags to enforce HTTP semantics */
@@ -132,11 +139,14 @@ typedef enum {
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
+ /* set if priority header field is received */
+ NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16,
+ /* set if an error is encountered while parsing priority header
+ field */
+ NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17,
} nghttp2_http_flag;
struct nghttp2_stream {
- /* Intrusive Map */
- nghttp2_map_entry map_entry;
/* Entry for dep_prev->obq */
nghttp2_pq_entry pq_entry;
/* Priority Queue storing direct descendant (nghttp2_stream). Only
@@ -206,7 +216,7 @@ struct nghttp2_stream {
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
- uint16_t http_flags;
+ uint32_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
@@ -220,6 +230,12 @@ struct nghttp2_stream {
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
is not queued. */
uint8_t window_update_queued;
+ /* extpri is a stream priority produced by nghttp2_extpri_to_uint8
+ used by RFC 9218 extensible priorities. */
+ uint8_t extpri;
+ /* http_extpri is a stream priority received in HTTP request header
+ fields and produced by nghttp2_extpri_to_uint8. */
+ uint8_t http_extpri;
};
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_submit.c b/Utilities/cmnghttp2/lib/nghttp2_submit.c
index f604eff..f5554eb 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_submit.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_submit.c
@@ -196,7 +196,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
flags &= NGHTTP2_FLAG_END_STREAM;
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, stream_id, pri_spec);
if (rv != 0) {
return rv;
@@ -229,6 +230,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
mem = &session->mem;
+ if (session->remote_settings.no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || pri_spec == NULL) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -450,6 +455,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (rv != 0) {
return rv;
}
+
+ if (window_size_increment > 0) {
+ return nghttp2_session_add_window_update(session, 0, stream_id,
+ window_size_increment);
+ }
+
+ return nghttp2_session_update_recv_connection_window_size(session, 0);
} else {
stream = nghttp2_session_get_stream(session, stream_id);
@@ -476,14 +488,15 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (rv != 0) {
return rv;
}
- }
- if (window_size_increment > 0) {
- return nghttp2_session_add_window_update(session, 0, stream_id,
- window_size_increment);
- }
+ if (window_size_increment > 0) {
+ return nghttp2_session_add_window_update(session, 0, stream_id,
+ window_size_increment);
+ }
- return 0;
+ return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
+ 1);
+ }
}
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
@@ -654,6 +667,78 @@ fail_item_malloc:
return rv;
}
+int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_mem *mem;
+ uint8_t *buf, *p;
+ nghttp2_outbound_item *item;
+ nghttp2_frame *frame;
+ nghttp2_ext_priority_update *priority_update;
+ int rv;
+ (void)flags;
+
+ mem = &session->mem;
+
+ if (session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities == 0) {
+ return 0;
+ }
+
+ if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (field_value_len) {
+ buf = nghttp2_mem_malloc(mem, field_value_len + 1);
+ if (buf == NULL) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+
+ p = nghttp2_cpymem(buf, field_value, field_value_len);
+ *p = '\0';
+ } else {
+ buf = NULL;
+ }
+
+ item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
+ if (item == NULL) {
+ rv = NGHTTP2_ERR_NOMEM;
+ goto fail_item_malloc;
+ }
+
+ nghttp2_outbound_item_init(item);
+
+ item->aux_data.ext.builtin = 1;
+
+ priority_update = &item->ext_frame_payload.priority_update;
+
+ frame = &item->frame;
+ frame->ext.payload = priority_update;
+
+ nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
+ field_value_len);
+
+ rv = nghttp2_session_add_item(session, item);
+ if (rv != 0) {
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ nghttp2_mem_free(mem, item);
+
+ return rv;
+ }
+
+ return 0;
+
+fail_item_malloc:
+ free(buf);
+
+ return rv;
+}
+
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) {
uint8_t flags = NGHTTP2_FLAG_NONE;
@@ -680,7 +765,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
return NGHTTP2_ERR_PROTO;
}
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, -1, pri_spec);
if (rv != 0) {
return rv;
diff --git a/Utilities/std/cm/bits/string_view.cxx b/Utilities/std/cm/bits/string_view.cxx
index 5381fe6..af5ae78 100644
--- a/Utilities/std/cm/bits/string_view.cxx
+++ b/Utilities/std/cm/bits/string_view.cxx
@@ -82,8 +82,8 @@ int string_view::compare(size_type pos1, size_type count1, const char* s,
return substr(pos1, count1).compare(string_view(s, count2));
}
-string_view::size_type string_view::find(string_view v, size_type pos) const
- noexcept
+string_view::size_type string_view::find(string_view v,
+ size_type pos) const noexcept
{
for (; pos + v.size_ <= size_; ++pos) {
if (std::char_traits<char>::compare(data_ + pos, v.data_, v.size_) == 0) {
@@ -109,8 +109,8 @@ string_view::size_type string_view::find(const char* s, size_type pos) const
return find(string_view(s), pos);
}
-string_view::size_type string_view::rfind(string_view v, size_type pos) const
- noexcept
+string_view::size_type string_view::rfind(string_view v,
+ size_type pos) const noexcept
{
if (size_ >= v.size_) {
for (pos = std::min(pos, size_ - v.size_) + 1; pos > 0;) {
@@ -151,8 +151,8 @@ string_view::size_type string_view::find_first_of(string_view v,
return npos;
}
-string_view::size_type string_view::find_first_of(char c, size_type pos) const
- noexcept
+string_view::size_type string_view::find_first_of(char c,
+ size_type pos) const noexcept
{
return find_first_of(string_view(&c, 1), pos);
}
@@ -183,8 +183,8 @@ string_view::size_type string_view::find_last_of(string_view v,
return npos;
}
-string_view::size_type string_view::find_last_of(char c, size_type pos) const
- noexcept
+string_view::size_type string_view::find_last_of(char c,
+ size_type pos) const noexcept
{
return find_last_of(string_view(&c, 1), pos);
}
@@ -201,9 +201,8 @@ string_view::size_type string_view::find_last_of(const char* s,
return find_last_of(string_view(s), pos);
}
-string_view::size_type string_view::find_first_not_of(string_view v,
- size_type pos) const
- noexcept
+string_view::size_type string_view::find_first_not_of(
+ string_view v, size_type pos) const noexcept
{
for (; pos < size_; ++pos) {
if (!traits_type::find(v.data_, v.size_, data_[pos])) {
@@ -213,9 +212,8 @@ string_view::size_type string_view::find_first_not_of(string_view v,
return npos;
}
-string_view::size_type string_view::find_first_not_of(char c,
- size_type pos) const
- noexcept
+string_view::size_type string_view::find_first_not_of(
+ char c, size_type pos) const noexcept
{
return find_first_not_of(string_view(&c, 1), pos);
}
@@ -233,9 +231,8 @@ string_view::size_type string_view::find_first_not_of(const char* s,
return find_first_not_of(string_view(s), pos);
}
-string_view::size_type string_view::find_last_not_of(string_view v,
- size_type pos) const
- noexcept
+string_view::size_type string_view::find_last_not_of(
+ string_view v, size_type pos) const noexcept
{
if (size_ > 0) {
for (pos = std::min(pos, size_ - 1) + 1; pos > 0;) {
@@ -248,9 +245,8 @@ string_view::size_type string_view::find_last_not_of(string_view v,
return npos;
}
-string_view::size_type string_view::find_last_not_of(char c,
- size_type pos) const
- noexcept
+string_view::size_type string_view::find_last_not_of(
+ char c, size_type pos) const noexcept
{
return find_last_not_of(string_view(&c, 1), pos);
}
diff --git a/Utilities/std/cm/string_view b/Utilities/std/cm/string_view
index 35cf5d9..320e1e7 100644
--- a/Utilities/std/cm/string_view
+++ b/Utilities/std/cm/string_view
@@ -157,8 +157,8 @@ public:
size_type count) const;
size_type find_first_not_of(const char* s, size_type pos = 0) const;
- size_type find_last_not_of(string_view v, size_type pos = npos) const
- noexcept;
+ size_type find_last_not_of(string_view v,
+ size_type pos = npos) const noexcept;
size_type find_last_not_of(char c, size_type pos = npos) const noexcept;
size_type find_last_not_of(const char* s, size_type pos,
size_type count) const;
diff --git a/Utilities/std/cmext/iterator b/Utilities/std/cmext/iterator
index 83d7890..eba10dd 100644
--- a/Utilities/std/cmext/iterator
+++ b/Utilities/std/cmext/iterator
@@ -39,10 +39,10 @@ using is_input_range =
std::is_pointer<Range>::value ||
std::is_array<Range>::value>;
#else
- cm::bool_constant<cm::is_input_iterator<decltype(
- std::begin(std::declval<const Range>()))>::value &&
- cm::is_input_iterator<decltype(
- std::end(std::declval<const Range>()))>::value>;
+ cm::bool_constant<cm::is_input_iterator<decltype(std::begin(
+ std::declval<const Range>()))>::value &&
+ cm::is_input_iterator<decltype(std::end(
+ std::declval<const Range>()))>::value>;
#endif
} // namespace cm