summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy2
-rw-r--r--.gitlab-ci.yml28
-rw-r--r--.gitlab/.gitignore1
-rw-r--r--.gitlab/ci/configure_fedora36_tidy.cmake2
-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/env_fedora36_tidy.sh7
-rwxr-xr-x.gitlab/ci/env_mingw_osdn_io_mingw_makefiles.ps13
-rwxr-xr-x.gitlab/ci/env_mingw_osdn_io_msys_makefiles.ps15
-rwxr-xr-x.gitlab/ci/mingw.ps125
-rw-r--r--.gitlab/os-windows.yml23
-rw-r--r--Auxiliary/vim/syntax/cmake.vim1
-rw-r--r--CMakeLists.txt41
-rw-r--r--CompileFlags.cmake5
-rw-r--r--Help/command/string.rst11
-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.rst2
-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/manual/cmake-file-api.7.rst30
-rw-r--r--Help/manual/cmake-policies.7.rst7
-rw-r--r--Help/policy/CMP0143.rst30
-rw-r--r--Help/prop_gbl/USE_FOLDERS.rst15
-rw-r--r--Help/prop_tgt/COMMON_LANGUAGE_RUNTIME.rst27
-rw-r--r--Help/release/dev/0-sample-topic.rst7
-rw-r--r--Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst6
-rw-r--r--Help/release/dev/UseSWIG-perl5.rst4
-rw-r--r--Help/release/dev/compile-commands-output-field.rst7
-rw-r--r--Help/release/dev/file-api-file-sets.rst9
-rw-r--r--Help/release/dev/timestamp-timezone.rst5
-rw-r--r--Help/release/dev/trace-try_compile.rst5
-rw-r--r--Help/release/dev/use-folder-on-by-default.rst5
-rw-r--r--Help/release/index.rst2
-rw-r--r--Modules/CMakeSwiftInformation.cmake26
-rw-r--r--Modules/ExternalProject.cmake34
-rw-r--r--Modules/FindBZip2.cmake21
-rw-r--r--Modules/FindLibLZMA.cmake18
-rw-r--r--Modules/FindZLIB.cmake75
-rw-r--r--Modules/GoogleTest.cmake6
-rw-r--r--Modules/Internal/CheckFlagCommonConfig.cmake2
-rw-r--r--Modules/Internal/CheckSourceCompiles.cmake11
-rw-r--r--Modules/UseSWIG.cmake7
-rw-r--r--Source/CMakeVersion.cmake4
-rw-r--r--Source/CTest/cmCTestConfigureCommand.cxx7
-rw-r--r--Source/CursesDialog/ccmake.cxx2
-rw-r--r--Source/QtDialog/CMakeSetup.cxx2
-rw-r--r--Source/cmExportFileGenerator.cxx4
-rw-r--r--Source/cmFileAPI.cxx2
-rw-r--r--Source/cmFileAPICodemodel.cxx111
-rw-r--r--Source/cmFindPackageCommand.cxx7
-rw-r--r--Source/cmGeneratedFileStream.cxx11
-rw-r--r--Source/cmGeneratorTarget.cxx11
-rw-r--r--Source/cmGlobalGenerator.cxx13
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx7
-rw-r--r--Source/cmGlobalNinjaGenerator.h3
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx6
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h3
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx8
-rw-r--r--Source/cmMakefile.cxx20
-rw-r--r--Source/cmMakefileProfilingData.cxx60
-rw-r--r--Source/cmMakefileProfilingData.h30
-rw-r--r--Source/cmMakefileTargetGenerator.cxx2
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx8
-rw-r--r--Source/cmNinjaTargetGenerator.cxx57
-rw-r--r--Source/cmNinjaTargetGenerator.h3
-rw-r--r--Source/cmPolicies.h5
-rw-r--r--Source/cmRulePlaceholderExpander.cxx5
-rw-r--r--Source/cmRulePlaceholderExpander.h2
-rw-r--r--Source/cmState.cxx2
-rw-r--r--Source/cmState.h1
-rw-r--r--Source/cmTimestamp.cxx63
-rw-r--r--Source/cmTimestamp.h4
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx7
-rw-r--r--Source/cmake.cxx21
-rw-r--r--Source/cmake.h27
-rw-r--r--Source/cmakemain.cxx2
-rw-r--r--Source/kwsys/ProcessUNIX.c13
-rw-r--r--Source/kwsys/Status.hxx.in10
-rw-r--r--Source/kwsys/SystemInformation.cxx6
-rw-r--r--Source/kwsys/SystemTools.cxx40
-rw-r--r--Templates/MSBuild/FlagTables/v142_CL.json7
-rw-r--r--Templates/MSBuild/FlagTables/v143_CL.json7
-rw-r--r--Tests/CMakeLists.txt56
-rw-r--r--Tests/CMakeOnly/AllFindModules/CMakeLists.txt4
-rw-r--r--Tests/CMakeTests/String-TIMESTAMP-TimeZone.cmake22
-rw-r--r--Tests/CMakeTests/StringTest.cmake.in3
-rw-r--r--Tests/CheckSourceTree/check.cmake8
-rw-r--r--Tests/CustomCommandByproducts/CMakeLists.txt35
-rw-r--r--Tests/CustomCommandByproducts/ExternalLibraryByproducts.c5
-rw-r--r--Tests/GeneratorExpression/CMakeLists.txt15
-rw-r--r--Tests/GeneratorExpression/check-part4.cmake9
-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.txt71
-rw-r--r--Tests/RunCMake/CXXModules/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/CXXModules/examples/circular-build-result.txt1
-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/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/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/CommandLine/E_capabilities-stdout.txt2
-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/RunCMakeTest.cmake9
-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/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/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/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/skip_test.cpp7
-rw-r--r--Tests/RunCMake/NinjaMultiConfig/CompileCommands-check.cmake6
-rw-r--r--Tests/RunCMake/RunCMake.cmake1
-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/alias_targets/duplicate-target-CMP0107-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/export/Repeat-CMP0103-OLD-stderr.txt10
-rw-r--r--Tests/RunCMake/string/Timestamp-stderr.txt2
-rw-r--r--Tests/RunCMake/string/Timestamp.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0108-OLD-self-link-stderr.txt10
-rw-r--r--Tests/RunCMake/try_compile/Inspect.cmake27
-rw-r--r--Tests/RunCMake/try_compile/RunCMakeTest.cmake21
-rw-r--r--Tests/SwiftMixLib/CMakeLists.txt3
-rw-r--r--Tests/SwiftMixLib/main.c3
-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--Utilities/ClangTidyModule/CMakeLists.txt31
-rw-r--r--Utilities/ClangTidyModule/Module.cxx30
-rw-r--r--Utilities/ClangTidyModule/Tests/CMakeLists.txt15
-rw-r--r--Utilities/ClangTidyModule/Tests/RunClangTidy.cmake63
-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.cxx37
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt20
-rw-r--r--Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx37
-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/UseBespokeEnumClassCheck.cxx35
-rw-r--r--Utilities/ClangTidyModule/UseBespokeEnumClassCheck.h21
-rw-r--r--Utilities/ClangTidyModule/UseCmstrlenCheck.cxx34
-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/Doxygen/CMakeLists.txt2
-rwxr-xr-xUtilities/Scripts/update-nghttp2.bash2
-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/lib/vtls/schannel.c7
-rw-r--r--Utilities/cmnghttp2/CMakeLists.txt1
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h1144
-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.h6
-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
265 files changed, 6252 insertions, 1116 deletions
diff --git a/.clang-tidy b/.clang-tidy
index a86f39a..18aa86e 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -33,6 +33,8 @@ readability-*,\
-readability-redundant-member-init,\
-readability-suspicious-call-argument,\
-readability-uppercase-literal-suffix,\
+cmake-*,\
+-cmake-use-bespoke-enum-class,\
"
HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$'
CheckOptions:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0e5824d..7f732a0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1060,6 +1060,34 @@ t:windows-clang13.0-gnu-nmake:
CMAKE_CI_BUILD_NAME: windows_clang13.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_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_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
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index d62e477..4988351 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -5,6 +5,7 @@
/ispc*
/jom
/llvm*
+/mingw
/msvc*
/ninja*
/open-watcom*
diff --git a/.gitlab/ci/configure_fedora36_tidy.cmake b/.gitlab/ci/configure_fedora36_tidy.cmake
index 38414d3..2d0eeeb 100644
--- a/.gitlab/ci/configure_fedora36_tidy.cmake
+++ b/.gitlab/ci/configure_fedora36_tidy.cmake
@@ -1,3 +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_fedora36_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/env_fedora36_tidy.sh b/.gitlab/ci/env_fedora36_tidy.sh
new file mode 100644
index 0000000..f9f08a3
--- /dev/null
+++ b/.gitlab/ci/env_fedora36_tidy.sh
@@ -0,0 +1,7 @@
+cmake \
+ -S Utilities/ClangTidyModule \
+ -B Utilities/ClangTidyModule/build \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DRUN_TESTS=ON
+cmake --build Utilities/ClangTidyModule/build
+ctest --test-dir Utilities/ClangTidyModule/build --output-on-failure
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/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/os-windows.yml b/.gitlab/os-windows.yml
index 5c6be11..271610b 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -236,6 +236,29 @@
variables:
CMAKE_CONFIGURATION: windows_openwatcom1.9
+.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:
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/CMakeLists.txt b/CMakeLists.txt
index 2b9eb2d..a61113a 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()
@@ -277,6 +267,16 @@ 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()
+
# 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 +286,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)
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/Help/command/string.rst b/Help/command/string.rst
index 86cbd2e..217157c 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/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..c020264 100644
--- a/Help/guide/tutorial/Installing and Testing.rst
+++ b/Help/guide/tutorial/Installing and Testing.rst
@@ -145,7 +145,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
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/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 4b8ac65..65defb6 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -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`,
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/policy/CMP0143.rst b/Help/policy/CMP0143.rst
new file mode 100644
index 0000000..7a7aee7
--- /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 and below, :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.
+
+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.
+
+This 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.
+The policy setting must be in scope at the end of the top-level
+``CMakeLists.txt`` file of the project and has global effect.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_gbl/USE_FOLDERS.rst b/Help/prop_gbl/USE_FOLDERS.rst
index 5919723..965b5d6 100644
--- a/Help/prop_gbl/USE_FOLDERS.rst
+++ b/Help/prop_gbl/USE_FOLDERS.rst
@@ -4,7 +4,16 @@ USE_FOLDERS
Use the :prop_tgt:`FOLDER` target property to organize targets into
folders.
-If not set, CMake treats this property as ``OFF`` by default. CMake
-generators that are capable of organizing into a hierarchy of folders
+.. versionchanged:: 3.26
+
+ CMake treats this property as ``ON`` by default.
+ See policy :policy:`CMP0143`.
+
+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.
+folders. (i.e.: Visual Studio / XCode)
+
+IDE's can also take advantage of this property to organize CMake targets.
+Regardless of generator support.
+
+See also the documentation for the :prop_tgt:`FOLDER` target property.
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/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst
new file mode 100644
index 0000000..233596f
--- /dev/null
+++ b/Help/release/dev/ExternalProject-INSTALL_BYPRODUCTS.rst
@@ -0,0 +1,6 @@
+ExternalProject-INSTALL_BYPRODUCTS
+----------------------------------
+
+* The :module:`ExternalProject` module :command:`ExternalProject_Add` command
+ gained an ``INSTALL_BYPRODUCTS`` option to specify files generated by the
+ "install" step.
diff --git a/Help/release/dev/UseSWIG-perl5.rst b/Help/release/dev/UseSWIG-perl5.rst
new file mode 100644
index 0000000..67d4161
--- /dev/null
+++ b/Help/release/dev/UseSWIG-perl5.rst
@@ -0,0 +1,4 @@
+UseSWIG-perl5
+-------------
+
+* The :module:`UseSWIG` module gained the support of ``perl5`` language.
diff --git a/Help/release/dev/compile-commands-output-field.rst b/Help/release/dev/compile-commands-output-field.rst
new file mode 100644
index 0000000..110fd4e
--- /dev/null
+++ b/Help/release/dev/compile-commands-output-field.rst
@@ -0,0 +1,7 @@
+compile-commands-output-field
+-----------------------------
+
+* The :prop_tgt:`EXPORT_COMPILE_COMMANDS` target property will now have the
+ ``output`` field in the compile commands objects. This allows multi-config
+ generators (namely :generator:`Ninja Multi-Config` generator) to contain the
+ compile commands for all configurations.
diff --git a/Help/release/dev/file-api-file-sets.rst b/Help/release/dev/file-api-file-sets.rst
new file mode 100644
index 0000000..8a8b8d3
--- /dev/null
+++ b/Help/release/dev/file-api-file-sets.rst
@@ -0,0 +1,9 @@
+file-api-file-sets
+------------------
+
+* 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.
diff --git a/Help/release/dev/timestamp-timezone.rst b/Help/release/dev/timestamp-timezone.rst
new file mode 100644
index 0000000..178fa9a
--- /dev/null
+++ b/Help/release/dev/timestamp-timezone.rst
@@ -0,0 +1,5 @@
+timestamp-timezone
+------------------
+
+* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` commands
+ now support the ``%z`` and ``%Z`` specifiers for the time zone.
diff --git a/Help/release/dev/trace-try_compile.rst b/Help/release/dev/trace-try_compile.rst
new file mode 100644
index 0000000..886aaad
--- /dev/null
+++ b/Help/release/dev/trace-try_compile.rst
@@ -0,0 +1,5 @@
+trace-try_compile
+-----------------
+
+* The :option:`cmake --trace` option now follows :command:`try_compile` and
+ :command:`try_run` invocations.
diff --git a/Help/release/dev/use-folder-on-by-default.rst b/Help/release/dev/use-folder-on-by-default.rst
new file mode 100644
index 0000000..4e91c2e
--- /dev/null
+++ b/Help/release/dev/use-folder-on-by-default.rst
@@ -0,0 +1,5 @@
+use-folder-on-by-default
+------------------------
+
+* Global property :prop_gbl:`USE_FOLDERS` is treated as ``ON`` by default.
+ See policy :policy:`CMP0143`.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index b6ecf7b..50e06bb 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@ CMake Release Notes
This file should include the adjacent "dev.txt" file
in development versions but not in release versions.
+.. include:: dev.txt
+
Releases
========
diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake
index 16726d2..62f7ef2 100644
--- a/Modules/CMakeSwiftInformation.cmake
+++ b/Modules/CMakeSwiftInformation.cmake
@@ -65,10 +65,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 +103,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 +111,11 @@ 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_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/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 22a25bd..9fecd8f 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -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
@@ -3642,7 +3659,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)
@@ -3846,6 +3863,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}]==]")
@@ -3854,6 +3876,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}
@@ -4081,6 +4104,7 @@ function(ExternalProject_Add name)
# Install step options
#
INSTALL_COMMAND
+ INSTALL_BYPRODUCTS
#
# Test step options
#
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/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
index 9ec8f07..c298bab 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 )
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/GoogleTest.cmake b/Modules/GoogleTest.cmake
index b8dc482..79e9437 100644
--- a/Modules/GoogleTest.cmake
+++ b/Modules/GoogleTest.cmake
@@ -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/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake
index c011c24..f8481cd 100644
--- a/Modules/Internal/CheckFlagCommonConfig.cmake
+++ b/Modules/Internal/CheckFlagCommonConfig.cmake
@@ -48,6 +48,8 @@ macro(CMAKE_CHECK_FLAG_COMMON_INIT _FUNC _LANG _SRC _PATTERNS)
FAIL_REGEX "argument unused during compilation: .*") # Clang
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..bf5a82d 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}
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index fd6596b..e0e01f5 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -378,6 +378,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 +415,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 +972,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/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 7491420..c215707 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 0)
-set(CMake_VERSION_RC 4)
+set(CMake_VERSION_PATCH 20221110)
+#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
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/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 1f7776c..70ed648 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -77,7 +77,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();
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index fb12b7d..591b793 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -79,7 +79,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();
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 50bc78c..2c61163 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -939,13 +939,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/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 7f8374d..3fc2179 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -687,7 +687,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)
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 0581802..56221a5 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)
{
@@ -466,9 +470,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 +1223,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 +1540,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/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 3f8378b..60b0a7b 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -377,6 +377,8 @@ 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
#endif
void ResetGenerator()
@@ -421,6 +423,11 @@ bool TryGeneratedPaths(CallbackFn&& filesCollector,
return false;
}
+#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
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/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 6195d1f..8fd7321 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5532,7 +5532,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;
@@ -8515,9 +8515,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(
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index c2bf888..a539d33 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -2943,19 +2943,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/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 077de42..395372b 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1171,7 +1171,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 =
@@ -1205,7 +1206,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 */
}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index defa264..dac1c52 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -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.
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 21aa89c..bf9e40e 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -143,7 +143,7 @@ void cmGlobalUnixMakefileGenerator3::Generate()
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 +164,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..92e567a 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -174,7 +174,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/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 0658021..62e5a1e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -4412,12 +4412,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()) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 6e0d704..2091f27 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -375,19 +375,15 @@ 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(lff, lfc);
#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 +395,9 @@ public:
private:
cmMakefile* Makefile;
+#if !defined(CMAKE_BOOTSTRAP)
+ cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII;
+#endif
};
void cmMakefile::OnExecuteCommand(std::function<void()> callback)
@@ -3584,6 +3583,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 +4472,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/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx
index 1cd97c9..e4844f3 100644
--- a/Source/cmMakefileProfilingData.cxx
+++ b/Source/cmMakefileProfilingData.cxx
@@ -4,8 +4,12 @@
#include <chrono>
#include <stdexcept>
+#include <type_traits>
+#include <utility>
#include <vector>
+#include <cm/utility>
+
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
@@ -46,6 +50,23 @@ cmMakefileProfilingData::~cmMakefileProfilingData() noexcept
void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff,
cmListFileContext const& lfc)
{
+ cm::optional<Json::Value> argsValue(cm::in_place, 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));
+ this->StartEntry("script", lff.LowerCaseName(), std::move(argsValue));
+}
+
+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()) {
return;
@@ -58,24 +79,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 +126,27 @@ void cmMakefileProfilingData::StopEntry()
cmSystemTools::Error("Error writing profiling output!");
}
}
+
+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..e8d7dfa 100644
--- a/Source/cmMakefileProfilingData.h
+++ b/Source/cmMakefileProfilingData.h
@@ -3,6 +3,11 @@
#pragma once
#include <memory>
#include <string>
+#include <utility>
+
+#include <cm/optional>
+
+#include <cm3p/json/value.h> // IWYU pragma: keep
#include "cmsys/FStream.hxx"
@@ -19,8 +24,33 @@ 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;
+
+ template <typename... Args>
+ RAII(cmMakefileProfilingData& data, Args&&... args)
+ : Data(&data)
+ {
+ this->Data->StartEntry(std::forward<Args>(args)...);
+ }
+
+ ~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..c5c5490 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -1031,7 +1031,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
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index bda8a5f..895a4c3 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -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";
@@ -1072,12 +1071,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
cmOutputConverter::SHELL);
}(vars["SWIFT_MODULE_NAME"]);
- const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config,
- '/', "output-file-map.json");
- vars["SWIFT_OUTPUT_FILE_MAP"] =
- this->GetLocalGenerator()->ConvertToOutputFormat(
- this->ConvertToNinjaPath(map), cmOutputConverter::SHELL);
-
vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
std::vector<cmSourceFile const*> sources;
std::stringstream oss;
@@ -1101,6 +1094,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.
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index e4427f5..fba0ff9 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1177,30 +1177,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;
+ }
- // 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 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"));
+ }();
- cmGeneratedFileStream output(mapFilePath);
- output << this->Configs[config].SwiftOutputMap;
- }
+ std::string mapFilePath =
+ cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/',
+ "output-file-map.json");
+
+ // 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 {
@@ -1998,7 +2010,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..c43b650 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -163,6 +163,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/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/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/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/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/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 4cfb561..c982713 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3316,9 +3316,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", "");
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 013a87b..36c0089 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -196,7 +196,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();
}
@@ -1542,6 +1542,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
@@ -2060,6 +2070,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) {
@@ -2572,6 +2586,11 @@ 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;
}
diff --git a/Source/cmake.h b/Source/cmake.h
index 3183577..2f7f7bd 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -33,6 +33,7 @@
# include <cm3p/json/value.h>
# include "cmCMakePresetsGraph.h"
+# include "cmMakefileProfilingData.h"
#endif
class cmExternalMakefileProjectGeneratorFactory;
@@ -41,9 +42,6 @@ class cmFileTimeCache;
class cmGlobalGenerator;
class cmGlobalGeneratorFactory;
class cmMakefile;
-#if !defined(CMAKE_BOOTSTRAP)
-class cmMakefileProfilingData;
-#endif
class cmMessenger;
class cmVariableWatch;
struct cmBuildOptions;
@@ -513,10 +511,19 @@ 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();
+ //! 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 +637,17 @@ public:
#if !defined(CMAKE_BOOTSTRAP)
cmMakefileProfilingData& GetProfilingOutput();
bool IsProfilingEnabled() const;
+
+ template <typename... Args>
+ cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry(
+ Args&&... args)
+ {
+ if (this->IsProfilingEnabled()) {
+ return cm::make_optional<cmMakefileProfilingData::RAII>(
+ this->GetProfilingOutput(), std::forward<Args>(args)...);
+ }
+ return cm::nullopt;
+ }
#endif
protected:
@@ -688,6 +706,7 @@ private:
bool TraceExpand = false;
TraceFormat TraceFormatVar = TRACE_HUMAN;
cmGeneratedFileStream TraceFile;
+ cmake* TraceRedirect = nullptr;
bool WarnUninitialized = false;
bool WarnUnusedCli = true;
bool CheckSystemVars = false;
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 723932e..43bebc1 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -208,7 +208,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();
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/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..fdd6b2d 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__
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/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 6e35df9..112455b 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")
@@ -2500,9 +2517,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/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/CheckSourceTree/check.cmake b/Tests/CheckSourceTree/check.cmake
index c2e3529..6341bd6 100644
--- a/Tests/CheckSourceTree/check.cmake
+++ b/Tests/CheckSourceTree/check.cmake
@@ -3,6 +3,14 @@ if(DEFINED ENV{CTEST_REAL_HOME})
set(ENV{HOME} "$ENV{CTEST_REAL_HOME}")
endif()
+file(GLOB known_files
+ "${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/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/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt
index ebbe288..6187966 100644
--- a/Tests/GeneratorExpression/CMakeLists.txt
+++ b/Tests/GeneratorExpression/CMakeLists.txt
@@ -261,13 +261,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-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/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..ad5cbb2 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -299,8 +299,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)
@@ -361,7 +361,7 @@ 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)
@@ -502,64 +502,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}})
@@ -752,11 +703,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})
@@ -896,13 +849,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/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
index 3f17c1f..921fabd 100644
--- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
@@ -120,7 +120,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}")
@@ -132,6 +134,10 @@ if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
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)
endif ()
# Tests which use named modules in shared libraries.
diff --git a/Tests/RunCMake/CXXModules/examples/circular-build-result.txt b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-result.txt
@@ -0,0 +1 @@
+1
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..433b461
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/circular-build-stdout.txt
@@ -0,0 +1 @@
+(Ninja generators)?(build stopped: dependency cycle:)
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/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/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/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index 1452c9b..969d8be 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":"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/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/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index a2eeddf..327b772 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -349,6 +349,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})
@@ -940,6 +947,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 +960,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/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/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/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/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/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/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/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index ba9cc3b..cc754e8 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -155,6 +155,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"
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/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/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/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_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/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/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
index 7245471..ad1cc29 100644
--- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake
@@ -1,5 +1,20 @@
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(NoArgs)
run_cmake(OneArg)
run_cmake(TwoArgs)
@@ -88,12 +103,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/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/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/Utilities/ClangTidyModule/CMakeLists.txt b/Utilities/ClangTidyModule/CMakeLists.txt
new file mode 100644
index 0000000..8e7b2bc
--- /dev/null
+++ b/Utilities/ClangTidyModule/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+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
+
+ UseBespokeEnumClassCheck.cxx
+ UseBespokeEnumClassCheck.h
+ UseCmstrlenCheck.cxx
+ UseCmstrlenCheck.h
+ UseCmsysFstreamCheck.cxx
+ UseCmsysFstreamCheck.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..ca9a812
--- /dev/null
+++ b/Utilities/ClangTidyModule/Module.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include <clang-tidy/ClangTidyModule.h>
+#include <clang-tidy/ClangTidyModuleRegistry.h>
+
+#include "UseBespokeEnumClassCheck.h"
+#include "UseCmstrlenCheck.h"
+#include "UseCmsysFstreamCheck.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");
+ }
+};
+
+static ClangTidyModuleRegistry::Add<CMakeClangTidyModule> X(
+ "cmake-clang-tidy", "Adds lint checks for the CMake code base.");
+}
+}
+}
diff --git a/Utilities/ClangTidyModule/Tests/CMakeLists.txt b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
new file mode 100644
index 0000000..2fedfa1
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/CMakeLists.txt
@@ -0,0 +1,15 @@
+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)
diff --git a/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
new file mode 100644
index 0000000..7fd7cdd
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/RunClangTidy.cmake
@@ -0,0 +1,63 @@
+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)
+
+set(command
+ "${CLANG_TIDY_COMMAND}"
+ "--load=${CLANG_TIDY_MODULE}"
+ "--checks=-*,${CHECK_NAME}"
+ "--fix"
+ "--format-style=file"
+ ${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()
+
+if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx")
+ set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}-fixit.cxx")
+else()
+ set(expect_fixit_file "${CMAKE_CURRENT_LIST_DIR}/${CHECK_NAME}.cxx")
+endif()
+file(READ "${expect_fixit_file}" expect_fixit)
+file(READ "${source_file}" actual_fixit)
+if(NOT expect_fixit STREQUAL actual_fixit)
+ string(REPLACE "\n" "\n " expect_fixit_formatted " ${expect_fixit}")
+ string(REPLACE "\n" "\n " actual_fixit_formatted " ${actual_fixit}")
+ string(APPEND RunClangTidy_TEST_FAILED "Expected fixit:\n${expect_fixit_formatted}\nActual fixit:\n${actual_fixit_formatted}\n")
+endif()
+
+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-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..c93d557
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-fixit.cxx
@@ -0,0 +1,37 @@
+#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");
+
+ // No correction needed
+ (void)ns2::strlen("Salve");
+ (void)cmStrLen("Konnichiwa");
+ (void)strlen(s0);
+
+ 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..6c52ad5
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen-stdout.txt
@@ -0,0 +1,20 @@
+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
diff --git a/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
new file mode 100644
index 0000000..f36262b
--- /dev/null
+++ b/Utilities/ClangTidyModule/Tests/cmake-use-cmstrlen.cxx
@@ -0,0 +1,37 @@
+#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");
+
+ // No correction needed
+ (void)ns2::strlen("Salve");
+ (void)cmStrLen("Konnichiwa");
+ (void)strlen(s0);
+
+ 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/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..590d260
--- /dev/null
+++ b/Utilities/ClangTidyModule/UseCmstrlenCheck.cxx
@@ -0,0 +1,34 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "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("callee")),
+ hasArgument(0, stringLiteral())),
+ this);
+}
+
+void UseCmstrlenCheck::check(const MatchFinder::MatchResult& Result)
+{
+ const Expr* Node = Result.Nodes.getNodeAs<Expr>("callee");
+
+ this->diag(Node->getBeginLoc(), "use cmStrLen() for string literals")
+ << FixItHint::CreateReplacement(Node->getSourceRange(), "cmStrLen");
+}
+}
+}
+}
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/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/Scripts/update-nghttp2.bash b/Utilities/Scripts/update-nghttp2.bash
index 07a8f13..bc76377 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.50.0"
readonly shortlog=false
readonly paths="
COPYING
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/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 454eb79..e022a2c 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -220,6 +220,7 @@ set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
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.
@@ -229,6 +230,7 @@ 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;
@@ -247,6 +249,7 @@ 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)) {
@@ -257,6 +260,10 @@ 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;
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/lib/includes/nghttp2/nghttp2.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
index e3aeb9f..61a14d9 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
@@ -1417,7 +1446,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 +1475,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 +1499,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 +1510,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 +1531,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 +1563,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 +1586,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 +1618,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 +1637,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 +1664,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 +1705,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 +1733,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 +1832,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 +1868,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 +1887,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 +1912,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 +1949,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 +1969,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 +2007,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 +2037,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 +2073,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 +2099,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 +2134,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 +2331,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 +2514,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 +2575,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 +2661,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 +2676,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 +2701,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 +2724,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 +2780,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 +2806,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 +2832,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 +2858,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 +2884,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 +2909,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 +2931,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 +2956,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 +2974,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 +3008,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 +3030,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 +3076,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 +3097,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 +3106,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 +3143,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 +3206,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 +3423,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 +3450,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 +3467,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 +3489,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 +3526,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 +3561,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 +3582,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 +3601,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 +3632,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 +3680,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 +3741,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 +3785,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 +3813,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 +3847,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 +3883,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 +3904,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 +3931,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 +3974,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 +4005,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 +4040,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 +4057,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 +4074,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 +4089,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 +4109,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 +4129,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 +4152,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 +4186,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 +4195,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 +4233,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 +4267,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 +4330,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 +4352,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 +4361,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 +4399,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 +4423,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 +4463,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 +4476,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 +4491,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 +4521,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 +4579,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 +4606,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 +4626,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 +4645,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 +4678,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 +4704,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 +4739,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 +4749,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 +4797,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 +4822,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 +4830,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 +4846,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 +5058,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 +5136,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 +5190,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 +5204,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 +5237,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 +5334,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 +5383,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 +5423,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 +5447,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 +5506,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 +5523,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 +5535,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 +5710,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/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..345f6c8 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;
}
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;